branch brought up to date
This commit is contained in:
@@ -0,0 +1 @@
|
||||
*~
|
||||
@@ -0,0 +1,3 @@
|
||||
*.o
|
||||
*.~
|
||||
applet/
|
||||
+284
-91
@@ -1,133 +1,326 @@
|
||||
#ifndef CONFIGURATION_H
|
||||
#define CONFIGURATION_H
|
||||
|
||||
// BASIC SETTINGS: select your board type, thermistor type, axis scaling, and endstop configuration
|
||||
// Uncomment ONE of the next three lines - the one for your RepRap machine
|
||||
#define REPRAPPRO_HUXLEY
|
||||
//#define REPRAPPRO_MENDEL
|
||||
//#define REPRAPPRO_WALLACE
|
||||
|
||||
//// The following define selects which electronics board you have. Please choose the one that matches your setup
|
||||
// Gen6 = 5,
|
||||
#define MOTHERBOARD 5
|
||||
#ifndef REPRAPPRO_HUXLEY
|
||||
#ifndef REPRAPPRO_MENDEL
|
||||
#ifndef REPRAPPRO_WALLACE
|
||||
#error Uncomment one of #define REPRAPPRO_HUXLEY, REPRAPPRO_MENDEL or REPRAPPRO_WALLACE at the start of the file Configuration.h
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//// Thermistor settings:
|
||||
// 1 is 100k thermistor
|
||||
// 2 is 200k thermistor
|
||||
// 3 is mendel-parts thermistor
|
||||
#define THERMISTORHEATER 3
|
||||
// Uncomment this if you are experimenting, know what you are doing, and want to switch off some safety
|
||||
// features, e.g. allow extrude at low temperature etc.
|
||||
//#define DEVELOPING
|
||||
|
||||
// This configurtion file contains the basic settings.
|
||||
// Advanced settings can be found in Configuration_adv.h
|
||||
// BASIC SETTINGS: select your board type, temperature sensor type, axis scaling, and endstop configuration
|
||||
|
||||
//// Calibration variables
|
||||
// X, Y, Z, E steps per unit - Metric Mendel / Orca with V9 extruder:
|
||||
float axis_steps_per_unit[] = {40, 40, 3333.92, 67};
|
||||
// For E steps per unit = 67 for v9 with direct drive (needs finetuning) for other extruders this needs to be changed
|
||||
// Metric Prusa Mendel with Makergear geared stepper extruder:
|
||||
//float axis_steps_per_unit[] = {80,80,3200/1.25,1380};
|
||||
|
||||
//// Endstop Settings
|
||||
#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors
|
||||
// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins.
|
||||
const bool ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops.
|
||||
// For optos H21LOB set to true, for Mendel-Parts newer optos TCST2103 set to false
|
||||
//User specified version info of THIS file to display in [Pronterface, etc] terminal window during startup.
|
||||
//Implementation of an idea by Prof Braino to inform user that any changes made
|
||||
//to THIS file by the user have been successfully uploaded into firmware.
|
||||
#define STRING_VERSION_CONFIG_H "2012-06-25-1" //Personal revision number for changes to THIS file.
|
||||
#define STRING_CONFIG_H_AUTHOR "RepRapPro" //Who made the changes.
|
||||
|
||||
// This determines the communication speed of the printer
|
||||
#define BAUDRATE 250000
|
||||
//#define BAUDRATE 115200
|
||||
|
||||
// Comment out (using // at the start of the line) to disable SD support:
|
||||
//#define SDSUPPORT
|
||||
//// The following define selects which electronics board you have. Please choose the one that matches your setup
|
||||
// Gen7 custom (Alfons3 Version) = 10 "https://github.com/Alfons3/Generation_7_Electronics"
|
||||
// Gen7 v1.1, v1.2 = 11
|
||||
// Gen7 v1.3 = 12
|
||||
// Gen7 v1.4 = 13
|
||||
// MEGA/RAMPS up to 1.2 = 3
|
||||
// RAMPS 1.3 = 33 (Power outputs: Extruder, Bed, Fan)
|
||||
// RAMPS 1.3 = 34 (Power outputs: Extruder0, Extruder1, Bed)
|
||||
// Gen6 = 5
|
||||
// Gen6 deluxe = 51
|
||||
// Sanguinololu 1.2 and above = 62
|
||||
// Melzi 63
|
||||
// Ultimaker = 7
|
||||
// Teensylu = 8
|
||||
// Gen3+ =9
|
||||
#define MOTHERBOARD 62
|
||||
|
||||
//===========================================================================
|
||||
//=============================Thermal Settings ============================
|
||||
//===========================================================================
|
||||
|
||||
// Set this if you want to define the constants in the thermistor circuit
|
||||
// and work out temperatures algebraically - added by AB.
|
||||
//#define COMPUTE_THERMISTORS
|
||||
|
||||
#ifdef COMPUTE_THERMISTORS
|
||||
|
||||
// See http://en.wikipedia.org/wiki/Thermistor#B_or_.CE.B2_parameter_equation
|
||||
|
||||
// BETA is the B value
|
||||
// RS is the value of the series resistor in ohms
|
||||
// R_INF is R0.exp(-BETA/T0), where R0 is the thermistor resistance at T0 (T0 is in kelvin)
|
||||
// Normally T0 is 298.15K (25 C). If you write that expression in brackets in the #define the compiler
|
||||
// should compute it for you (i.e. it won't need to be calculated at run time).
|
||||
|
||||
// If the A->D converter has a range of 0..1023 and the measured voltage is V (between 0 and 1023)
|
||||
// then the thermistor resistance, R = V.RS/(1023 - V)
|
||||
// and the temperature, T = BETA/ln(R/R_INF)
|
||||
// To get degrees celsius (instead of kelvin) add -273.15 to T
|
||||
|
||||
// This DOES assume that all extruders use the same thermistor type.
|
||||
|
||||
#define ABS_ZERO -273.15
|
||||
#define AD_RANGE 16383
|
||||
|
||||
// RS 198-961
|
||||
#define E_BETA 3960.0
|
||||
#define E_RS 4700.0
|
||||
#define E_R_INF ( 100000.0*exp(-E_BETA/298.15) )
|
||||
|
||||
// RS 484-0149; EPCOS B57550G103J
|
||||
#define BED_BETA 3480.0
|
||||
#define BED_RS 4700.0
|
||||
#define BED_R_INF ( 10000.0*exp(-BED_BETA/298.15) )
|
||||
|
||||
#define BED_USES_THERMISTOR
|
||||
#define HEATER_0_USES_THERMISTOR
|
||||
//#define HEATER_1_USES_THERMISTOR
|
||||
//#define HEATER_2_USES_THERMISTOR
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//// ADVANCED SETTINGS - to tweak parameters
|
||||
|
||||
#include "thermistortables.h"
|
||||
//// Temperature sensor settings:
|
||||
// -2 is thermocouple with MAX6675 (only for sensor 0)
|
||||
// -1 is thermocouple with AD595
|
||||
// 0 is not used
|
||||
// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
|
||||
// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
|
||||
// 3 is mendel-parts thermistor (4.7k pullup)
|
||||
// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
|
||||
// 5 is ParCan supplied 104GT-2 100K
|
||||
// 6 is EPCOS 100k
|
||||
// 7 is 100k Honeywell thermistor 135-104LAG-J01
|
||||
// 100 is 100k GE Sensing AL03006-58.2K-97-G1 with r2=4k7
|
||||
// 101 is 100k 0603 SMD Vishay NTCS0603E3104FXT with r2=4k7
|
||||
// 102 is 100k EPCOS G57540 Nozzle with r2=4k7
|
||||
// 103 is 100k EPCOS G57540 Bed with r2=4k7
|
||||
// 104 is 10k G57540 Bed with r2=4k7
|
||||
// 105 is 10k G57540 Bed with r2=10k
|
||||
// 110 is 100k RS thermistor 198-961 hot end with 10K resistor
|
||||
|
||||
#define TEMP_SENSOR_0 102
|
||||
#define TEMP_SENSOR_1 0
|
||||
#define TEMP_SENSOR_2 0
|
||||
#define TEMP_SENSOR_BED 101
|
||||
|
||||
// Actual temperature must be close to target for this long before M109 returns success
|
||||
#define TEMP_RESIDENCY_TIME 10 // (seconds)
|
||||
#define TEMP_HYSTERESIS 5 // (C°) range of +/- temperatures considered "close" to the target one
|
||||
#define TEMP_WINDOW 2 // (degC) Window around target to start the recidency timer x degC early.
|
||||
|
||||
// The minimal temperature defines the temperature below which the heater will not be enabled It is used
|
||||
// to check that the wiring to the thermistor is not broken.
|
||||
// Otherwise this would lead to the heater being powered on all the time.
|
||||
#define HEATER_0_MINTEMP 1
|
||||
//#define HEATER_1_MINTEMP 5
|
||||
//#define HEATER_2_MINTEMP 5
|
||||
#define BED_MINTEMP 1
|
||||
|
||||
// When temperature exceeds max temp, your heater will be switched off.
|
||||
// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure!
|
||||
// You should use MINTEMP for thermistor short/failure protection.
|
||||
#define HEATER_0_MAXTEMP 399
|
||||
//#define HEATER_1_MAXTEMP 275
|
||||
//#define HEATER_2_MAXTEMP 275
|
||||
#define BED_MAXTEMP 150
|
||||
|
||||
|
||||
// PID settings:
|
||||
// Comment the following line to disable PID and enable bang-bang.
|
||||
#define PIDTEMP
|
||||
#define PID_MAX 255 // limits current to nozzle; 255=full current
|
||||
#define FULL_PID_BAND 150 // Full power is applied when pid_error[e] > FULL_PID_BAND
|
||||
#ifdef PIDTEMP
|
||||
//#define PID_DEBUG // Sends debug data to the serial port.
|
||||
//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in %
|
||||
#define PID_INTEGRAL_DRIVE_MAX 125 //limit for the integral term
|
||||
#define K1 0.95 //smoothing factor withing the PID
|
||||
#define PID_dT 0.122 //sampling period of the PID
|
||||
|
||||
// If you are using a preconfigured hotend then you can use one of the value sets by uncommenting it
|
||||
// Ultimaker
|
||||
// #define DEFAULT_Kp 22.2
|
||||
// #define DEFAULT_Ki (1.25*PID_dT)
|
||||
// #define DEFAULT_Kd (99/PID_dT)
|
||||
|
||||
// Makergear
|
||||
// #define DEFAULT_Kp 7.0
|
||||
// #define DEFAULT_Ki 0.1
|
||||
// #define DEFAULT_Kd 12
|
||||
|
||||
// RepRapPro Huxley + Mendel
|
||||
#define DEFAULT_Kp 12.0
|
||||
#define DEFAULT_Ki (2.2*PID_dT)
|
||||
#define DEFAULT_Kd (80/PID_dT)
|
||||
|
||||
// Mendel Parts V9 on 12V
|
||||
// #define DEFAULT_Kp 63.0
|
||||
// #define DEFAULT_Ki (2.25*PID_dT)
|
||||
// #define DEFAULT_Kd (440/PID_dT)
|
||||
#endif // PIDTEMP
|
||||
|
||||
#ifndef DEVELOPING
|
||||
//this prevents dangerous Extruder moves, i.e. if the temperature is under the limit
|
||||
//can be software-disabled for whatever purposes by
|
||||
#define PREVENT_DANGEROUS_EXTRUDE
|
||||
#define EXTRUDE_MINTEMP 170
|
||||
#define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances.
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//=============================Mechanical Settings===========================
|
||||
//===========================================================================
|
||||
|
||||
// Endstop Settings
|
||||
#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors
|
||||
|
||||
// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins.
|
||||
const bool X_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops.
|
||||
const bool Y_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops.
|
||||
const bool Z_ENDSTOPS_INVERTING = false; // set to true to invert the logic of the endstops.
|
||||
|
||||
// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1
|
||||
#define X_ENABLE_ON 0
|
||||
#define Y_ENABLE_ON 0
|
||||
#define Z_ENABLE_ON 0
|
||||
#define E_ENABLE_ON 0
|
||||
#define E_ENABLE_ON 0 // For all extruders
|
||||
|
||||
// Disables axis when it's not being used.
|
||||
#define DISABLE_X false
|
||||
#define DISABLE_Y false
|
||||
#define DISABLE_Z true
|
||||
#define DISABLE_E false
|
||||
#define DISABLE_E false // For all extruders
|
||||
|
||||
// Inverting axis direction
|
||||
#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true
|
||||
#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false
|
||||
#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true
|
||||
#define INVERT_E_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false
|
||||
#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false
|
||||
#define INVERT_Z_DIR false // for Mendel set to false, for Orca set to true
|
||||
#define INVERT_E0_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false
|
||||
#define INVERT_E1_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false
|
||||
#define INVERT_E2_DIR true // for direct drive extruder v9 set to true, for geared extruder set to false
|
||||
|
||||
//// ENDSTOP SETTINGS:
|
||||
// ENDSTOP SETTINGS:
|
||||
// Sets direction of endstops when homing; 1=MAX, -1=MIN
|
||||
#define X_HOME_DIR -1
|
||||
#define Y_HOME_DIR -1
|
||||
#define Z_HOME_DIR -1
|
||||
|
||||
#define min_software_endstops false //If true, axis won't move to coordinates less than zero.
|
||||
#define min_software_endstops true //If true, axis won't move to coordinates less than zero.
|
||||
#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below.
|
||||
#define X_MAX_LENGTH 200
|
||||
#define Y_MAX_LENGTH 200
|
||||
#define Z_MAX_LENGTH 100
|
||||
|
||||
// The position of the homing switches. Use MAX_LENGTH * -0.5 if the center should be 0, 0, 0
|
||||
#define X_HOME_POS 0
|
||||
#define Y_HOME_POS 0
|
||||
#define Z_HOME_POS 0
|
||||
|
||||
//// MOVEMENT SETTINGS
|
||||
#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
|
||||
float max_feedrate[] = {60000, 60000, 100, 500000}; // set the max speeds
|
||||
float homing_feedrate[] = {2400, 2400, 80, 0}; // set the homing speeds
|
||||
bool axis_relative_modes[] = {false, false, false, false};
|
||||
|
||||
//// Acceleration settings
|
||||
// X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot.
|
||||
float acceleration = 2000; // Normal acceleration mm/s^2
|
||||
float retract_acceleration = 7000; // Normal acceleration mm/s^2
|
||||
float max_xy_jerk = 20.0*60;
|
||||
float max_z_jerk = 0.4*60;
|
||||
long max_acceleration_units_per_sq_second[] = {7000,7000,100,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts
|
||||
#ifdef REPRAPPRO_MENDEL
|
||||
|
||||
// The watchdog waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature
|
||||
// If the temperature has not increased at the end of that period, the target temperature is set to zero. It can be reset with another M104/M109
|
||||
//#define WATCHPERIOD 5000 //5 seconds
|
||||
#define X_MAX_LENGTH 210
|
||||
#define Y_MAX_LENGTH 210
|
||||
#define Z_MAX_LENGTH 140
|
||||
#define HOMING_FEEDRATE {10*60, 10*60, 1*60, 0} // set the homing speeds (mm/min)
|
||||
#define FAST_HOME_FEEDRATE {50*60, 50*60, 1*60, 0} // set the homing speeds (mm/min)
|
||||
#define DEFAULT_MAX_FEEDRATE {500, 500, 3, 45}
|
||||
#define DEFAULT_MAX_FEEDRATE {300, 300, 3, 45} // (mm/sec)
|
||||
#define DEFAULT_MAX_ACCELERATION {800,800,30,250} // X, Y, Z, E maximum start speed for accelerated moves. E default values
|
||||
|
||||
//// The minimal temperature defines the temperature below which the heater will not be enabled
|
||||
#define MINTEMP 5
|
||||
#else
|
||||
|
||||
|
||||
// When temperature exceeds max temp, your heater will be switched off.
|
||||
// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure!
|
||||
// You should use MINTEMP for thermistor short/failure protection.
|
||||
#define MAXTEMP 275
|
||||
|
||||
|
||||
/// PID settings:
|
||||
// Uncomment the following line to enable PID support.
|
||||
//#define PIDTEMP
|
||||
#ifdef PIDTEMP
|
||||
//#define PID_DEBUG 1 // Sends debug data to the serial port.
|
||||
//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in %
|
||||
#define PID_MAX 156 // limits current to nozzle
|
||||
#define PID_INTEGRAL_DRIVE_MAX 156.0
|
||||
#define PID_dT 0.16
|
||||
double Kp = 20.0;
|
||||
double Ki = 1.5*PID_dT;
|
||||
double Kd = 80/PID_dT;
|
||||
#endif // PIDTEMP
|
||||
|
||||
|
||||
// extruder advance constant (s2/mm3)
|
||||
//
|
||||
// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2
|
||||
//
|
||||
// hooke's law says: force = k * distance
|
||||
// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant
|
||||
// so: v ^ 2 is proportional to number of steps we advance the extruder
|
||||
//#define ADVANCE
|
||||
|
||||
#ifdef ADVANCE
|
||||
#define EXTRUDER_ADVANCE_K 0.02
|
||||
|
||||
#define D_FILAMENT 1.7
|
||||
#define STEPS_MM_E 65
|
||||
#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159)
|
||||
#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA)
|
||||
|
||||
#endif // ADVANCE
|
||||
#define X_MAX_LENGTH 155
|
||||
#define Y_MAX_LENGTH 150
|
||||
#define Z_MAX_LENGTH 90
|
||||
#define HOMING_FEEDRATE {10*60, 10*60, 1*60, 0} // set the homing speeds (mm/min)
|
||||
#define FAST_HOME_FEEDRATE {80*60, 80*60, 4*60, 0} // set the homing speeds (mm/min)
|
||||
#define DEFAULT_MAX_FEEDRATE {500, 500, 5, 45} // (mm/sec)
|
||||
#define DEFAULT_MAX_FEEDRATE {500, 500, 5, 45} // (mm/sec)
|
||||
#define DEFAULT_MAX_ACCELERATION {1000,1000,50,250} // X, Y, Z, E maximum start speed for accelerated moves. E default values
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// default settings
|
||||
|
||||
#define DEFAULT_AXIS_STEPS_PER_UNIT {91.4286, 91.4286,4000,875} // default steps per unit for ultimaker
|
||||
|
||||
|
||||
#define DEFAULT_ACCELERATION 1000 // X, Y, Z and E max acceleration in mm/s^2 for printing moves
|
||||
#define DEFAULT_RETRACT_ACCELERATION 1000 // X, Y, Z and E max acceleration in mm/s^2 for r retracts
|
||||
|
||||
//
|
||||
#define DEFAULT_XYJERK 15.0 // (mm/sec)
|
||||
#define DEFAULT_ZJERK 0.4 // (mm/sec)
|
||||
#define DEFAULT_EJERK 15.0 // (mm/sec)
|
||||
|
||||
//===========================================================================
|
||||
//=============================Additional Features===========================
|
||||
//===========================================================================
|
||||
|
||||
// EEPROM
|
||||
// the microcontroller can store settings in the EEPROM, e.g. max velocity...
|
||||
// M500 - stores paramters in EEPROM
|
||||
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
|
||||
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
|
||||
//define this to enable eeprom support
|
||||
#define EEPROM_SETTINGS
|
||||
//to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out:
|
||||
// please keep turned on if you can.
|
||||
#define EEPROM_CHITCHAT
|
||||
|
||||
//LCD and SD support
|
||||
//#define ULTRA_LCD //general lcd support, also 16x2
|
||||
#define SDSUPPORT // Enable SD Card Support in Hardware Console
|
||||
|
||||
//#define ULTIPANEL
|
||||
#ifdef ULTIPANEL
|
||||
//#define NEWPANEL //enable this if you have a click-encoder panel
|
||||
#define SDSUPPORT
|
||||
#define ULTRA_LCD
|
||||
#define LCD_WIDTH 20
|
||||
#define LCD_HEIGHT 4
|
||||
|
||||
// Preheat Constants
|
||||
#define PLA_PREHEAT_HOTEND_TEMP 180
|
||||
#define PLA_PREHEAT_HPB_TEMP 70
|
||||
#define PLA_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255
|
||||
|
||||
#define ABS_PREHEAT_HOTEND_TEMP 240
|
||||
#define ABS_PREHEAT_HPB_TEMP 100
|
||||
#define ABS_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255
|
||||
|
||||
#else //no panel but just lcd
|
||||
#ifdef ULTRA_LCD
|
||||
#define LCD_WIDTH 16
|
||||
#define LCD_HEIGHT 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable uM-FPU support:
|
||||
#define UMFPUSUPPORT 1
|
||||
|
||||
// M240 Triggers a camera by emulating a Canon RC-1 Remote
|
||||
// Data from: http://www.doc-diy.net/photo/rc-1_hacked/
|
||||
// #define PHOTOGRAPH_PIN 23
|
||||
|
||||
#include "Configuration_adv.h"
|
||||
#include "thermistortables.h"
|
||||
|
||||
#endif //__CONFIGURATION_H
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
#ifndef CONFIGURATION_ADV_H
|
||||
#define CONFIGURATION_ADV_H
|
||||
|
||||
//===========================================================================
|
||||
//=============================Thermal Settings ============================
|
||||
//===========================================================================
|
||||
|
||||
// Select one of these only to define how the bed temp is read.
|
||||
//
|
||||
//#define BED_LIMIT_SWITCHING
|
||||
#ifdef BED_LIMIT_SWITCHING
|
||||
#define BED_HYSTERESIS 2 //only disable heating if T>target+BED_HYSTERESIS and enable heating if T>target-BED_HYSTERESIS
|
||||
#endif
|
||||
#define BED_CHECK_INTERVAL 5000 //ms
|
||||
|
||||
//// Heating sanity check:
|
||||
// This waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature
|
||||
// If the temperature has not increased at the end of that period, the target temperature is set to zero.
|
||||
// It can be reset with another M104/M109
|
||||
//#define WATCHPERIOD 20000 //20 seconds
|
||||
|
||||
// Wait for Cooldown
|
||||
// This defines if the M109 call should not block if it is cooling down.
|
||||
// example: From a current temp of 220, you set M109 S200.
|
||||
// if CooldownNoWait is defined M109 will not wait for the cooldown to finish
|
||||
#define CooldownNoWait true
|
||||
|
||||
#ifdef PIDTEMP
|
||||
// this adds an experimental additional term to the heatingpower, proportional to the extrusion speed.
|
||||
// if Kc is choosen well, the additional required power due to increased melting should be compensated.
|
||||
//#define PID_ADD_EXTRUSION_RATE
|
||||
#ifdef PID_ADD_EXTRUSION_RATE
|
||||
#define DEFAULT_Kc (1) //heatingpower=Kc*(e_speed)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
//automatic temperature: The hot end target temperature is calculated by all the buffered lines of gcode.
|
||||
//The maximum buffered steps/sec of the extruder motor are called "se".
|
||||
//You enter the autotemp mode by a M109 S<mintemp> T<maxtemp> F<factor>
|
||||
// the target temperature is set to mintemp+factor*se[steps/sec] and limited by mintemp and maxtemp
|
||||
// you exit the value by any M109 without F*
|
||||
// Also, if the temperature is set to a value <mintemp, it is not changed by autotemp.
|
||||
// on an ultimaker, some initial testing worked with M109 S215 T260 F0.1 in the start.gcode
|
||||
//#define AUTOTEMP
|
||||
#ifdef AUTOTEMP
|
||||
#define AUTOTEMP_OLDWEIGHT 0.98
|
||||
#endif
|
||||
|
||||
// extruder run-out prevention.
|
||||
//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
|
||||
//#define EXTRUDER_RUNOUT_PREVENT
|
||||
#define EXTRUDER_RUNOUT_MINTEMP 175
|
||||
#define EXTRUDER_RUNOUT_SECONDS 30.
|
||||
#define EXTRUDER_RUNOUT_ESTEPS 14. //mm filament
|
||||
#define EXTRUDER_RUNOUT_SPEED 1500. //extrusion speed
|
||||
#define EXTRUDER_RUNOUT_EXTRUDE 100
|
||||
|
||||
//These defines help to calibrate the AD595 sensor in case you get wrong temperature measurements.
|
||||
//The measured temperature is defined as "actualTemp = (measuredTemp * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET"
|
||||
#define TEMP_SENSOR_AD595_OFFSET 0.0
|
||||
#define TEMP_SENSOR_AD595_GAIN 1.0
|
||||
|
||||
//This is for controlling a fan to cool down the stepper drivers
|
||||
//it will turn on when any driver is enabled
|
||||
//and turn off after the set amount of seconds from last driver being disabled again
|
||||
//#define CONTROLLERFAN_PIN 23 //Pin used for the fan to cool controller, comment out to disable this function
|
||||
#define CONTROLLERFAN_SEC 60 //How many seconds, after all motors were disabled, the fan should run
|
||||
|
||||
//===========================================================================
|
||||
//=============================Mechanical Settings===========================
|
||||
//===========================================================================
|
||||
|
||||
// This defines the number of extruders
|
||||
#define EXTRUDERS 1
|
||||
|
||||
#define Z_INCREMENT .0040 //Probe Movement Increment - 1 Full step on Huxley = 1/250
|
||||
#define PROBE_N 3
|
||||
|
||||
#define ENDSTOPS_ONLY_FOR_HOMING // If defined the endstops will only be used for homing
|
||||
|
||||
//#define Z_LATE_ENABLE // Enable Z the last moment. Needed if your Z driver overheats.
|
||||
|
||||
//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
|
||||
#define X_HOME_RETRACT_MM 4
|
||||
#define Y_HOME_RETRACT_MM 4
|
||||
#define Z_HOME_RETRACT_MM 2
|
||||
//#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially.
|
||||
|
||||
#define AXIS_RELATIVE_MODES {false, false, false, false}
|
||||
|
||||
#define MAX_STEP_FREQUENCY 50000 // Max step frequency for Ultimaker (5000 pps / half step)
|
||||
|
||||
//default stepper release if idle
|
||||
#define DEFAULT_STEPPER_DEACTIVE_TIME 60
|
||||
|
||||
#define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate
|
||||
#define DEFAULT_MINTRAVELFEEDRATE 0.0
|
||||
|
||||
// minimum time in microseconds that a movement needs to take if the buffer is emptied. Increase this number if you see blobs while printing high speed & high detail. It will slowdown on the detailed stuff.
|
||||
#define DEFAULT_MINSEGMENTTIME 20000 // Obsolete delete this
|
||||
|
||||
// If defined the movements slow down when the look ahead buffer is only half full
|
||||
#define SLOWDOWN
|
||||
|
||||
// Frequency limit
|
||||
// See nophead's blog for more info
|
||||
// Not working O
|
||||
//#define XY_FREQUENCY_LIMIT 15
|
||||
|
||||
// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end
|
||||
// of the buffer and all stops. This should not be much greater than zero and should only be changed
|
||||
// if unwanted behavior is observed on a user's machine when running at very slow speeds.
|
||||
#define MINIMUM_PLANNER_SPEED 2.0 // (mm/sec)
|
||||
|
||||
//===========================================================================
|
||||
//=============================Additional Features===========================
|
||||
//===========================================================================
|
||||
|
||||
|
||||
#define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers?
|
||||
#define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // no z because of layer shift.
|
||||
|
||||
// The hardware watchdog should halt the Microcontroller, in case the firmware gets stuck somewhere. However:
|
||||
// the Watchdog is not working well, so please only enable this for testing
|
||||
// this enables the watchdog interrupt.
|
||||
//#define USE_WATCHDOG
|
||||
//#ifdef USE_WATCHDOG
|
||||
// you cannot reboot on a mega2560 due to a bug in he bootloader. Hence, you have to reset manually, and this is done hereby:
|
||||
//#define RESET_MANUAL
|
||||
//#define WATCHDOG_TIMEOUT 4 //seconds
|
||||
//#endif
|
||||
|
||||
// extruder advance constant (s2/mm3)
|
||||
//
|
||||
// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2
|
||||
//
|
||||
// hooke's law says: force = k * distance
|
||||
// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant
|
||||
// so: v ^ 2 is proportional to number of steps we advance the extruder
|
||||
//#define ADVANCE
|
||||
|
||||
#ifdef ADVANCE
|
||||
#define EXTRUDER_ADVANCE_K .0
|
||||
|
||||
#define D_FILAMENT 2.85
|
||||
#define STEPS_MM_E 836
|
||||
#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159)
|
||||
#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA)
|
||||
|
||||
#endif // ADVANCE
|
||||
|
||||
// Arc interpretation settings:
|
||||
#define MM_PER_ARC_SEGMENT 1
|
||||
#define N_ARC_CORRECTION 25
|
||||
|
||||
const int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement
|
||||
|
||||
// If you are using a RAMPS board or cheap E-bay purchased boards that do not detect when an SD card is inserted
|
||||
// You can get round this by connecting a push button or single throw switch to the pin defined as SDCARDCARDDETECT
|
||||
// in the pins.h file. When using a push button pulling the pin to ground this will need inverted. This setting should
|
||||
// be commented out otherwise
|
||||
//#define SDCARDDETECTINVERTED
|
||||
|
||||
//===========================================================================
|
||||
//=============================Buffers ============================
|
||||
//===========================================================================
|
||||
|
||||
// The number of linear motions that can be in the plan at any give time.
|
||||
// THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2, i.g. 8,16,32 because shifts and ors are used to do the ringbuffering.
|
||||
#if defined SDSUPPORT
|
||||
#define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller
|
||||
// Chuck size for fast sd transfer
|
||||
#define SD_FAST_XFER_CHUNK_SIZE 1024
|
||||
#else
|
||||
#define BLOCK_BUFFER_SIZE 16 // maximize block buffer
|
||||
#endif
|
||||
|
||||
|
||||
//The ASCII buffer for recieving from the serial:
|
||||
#define MAX_CMD_SIZE 96
|
||||
#define BUFSIZE 4
|
||||
|
||||
//===========================================================================
|
||||
//============================= Define Defines ============================
|
||||
//===========================================================================
|
||||
|
||||
#if TEMP_SENSOR_0 > 0
|
||||
#define THERMISTORHEATER_0 TEMP_SENSOR_0
|
||||
#define HEATER_0_USES_THERMISTOR
|
||||
#endif
|
||||
#if TEMP_SENSOR_1 > 0
|
||||
#define THERMISTORHEATER_1 TEMP_SENSOR_1
|
||||
#define HEATER_1_USES_THERMISTOR
|
||||
#endif
|
||||
#if TEMP_SENSOR_2 > 0
|
||||
#define THERMISTORHEATER_2 TEMP_SENSOR_2
|
||||
#define HEATER_2_USES_THERMISTOR
|
||||
#endif
|
||||
#if TEMP_SENSOR_BED > 0
|
||||
#define THERMISTORBED TEMP_SENSOR_BED
|
||||
#define BED_USES_THERMISTOR
|
||||
#endif
|
||||
#if TEMP_SENSOR_0 == -1
|
||||
#define HEATER_0_USES_AD595
|
||||
#endif
|
||||
#if TEMP_SENSOR_1 == -1
|
||||
#define HEATER_1_USES_AD595
|
||||
#endif
|
||||
#if TEMP_SENSOR_2 == -1
|
||||
#define HEATER_2_USES_AD595
|
||||
#endif
|
||||
#if TEMP_SENSOR_BED == -1
|
||||
#define BED_USES_AD595
|
||||
#endif
|
||||
#if TEMP_SENSOR_0 == -2
|
||||
#define HEATER_0_USES_MAX6675
|
||||
#endif
|
||||
#if TEMP_SENSOR_0 == 0
|
||||
#undef HEATER_0_MINTEMP
|
||||
#undef HEATER_0_MAXTEMP
|
||||
#endif
|
||||
#if TEMP_SENSOR_1 == 0
|
||||
#undef HEATER_1_MINTEMP
|
||||
#undef HEATER_1_MAXTEMP
|
||||
#endif
|
||||
#if TEMP_SENSOR_2 == 0
|
||||
#undef HEATER_2_MINTEMP
|
||||
#undef HEATER_2_MAXTEMP
|
||||
#endif
|
||||
#if TEMP_SENSOR_BED == 0
|
||||
#undef BED_MINTEMP
|
||||
#undef BED_MAXTEMP
|
||||
#endif
|
||||
|
||||
|
||||
#endif //__CONFIGURATION_ADV_H
|
||||
@@ -0,0 +1,218 @@
|
||||
#ifndef EEPROM_H
|
||||
#define EEPROM_H
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "planner.h"
|
||||
#include "temperature.h"
|
||||
#include "FPUTransform.h"
|
||||
//#include <EEPROM.h>
|
||||
|
||||
|
||||
|
||||
template <class T> int EEPROM_writeAnything(int &ee, const T& value)
|
||||
{
|
||||
const byte* p = (const byte*)(const void*)&value;
|
||||
int i;
|
||||
for (i = 0; i < (int)sizeof(value); i++)
|
||||
eeprom_write_byte((unsigned char *)ee++, *p++);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class T> int EEPROM_readAnything(int &ee, T& value)
|
||||
{
|
||||
byte* p = (byte*)(void*)&value;
|
||||
int i;
|
||||
for (i = 0; i < (int)sizeof(value); i++)
|
||||
*p++ = eeprom_read_byte((unsigned char *)ee++);
|
||||
return i;
|
||||
}
|
||||
//======================================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
#define EEPROM_OFFSET 100
|
||||
|
||||
|
||||
// IMPORTANT: Whenever there are changes made to the variables stored in EEPROM
|
||||
// in the functions below, also increment the version number. This makes sure that
|
||||
// the default values are used whenever there is a change to the data, to prevent
|
||||
// wrong data being written to the variables.
|
||||
// ALSO: always make sure the variables in the Store and retrieve sections are in the same order.
|
||||
#define EEPROM_VERSION "V05"
|
||||
|
||||
inline void EEPROM_StoreSettings()
|
||||
{
|
||||
#ifdef EEPROM_SETTINGS
|
||||
char ver[4]= "000";
|
||||
int i=EEPROM_OFFSET;
|
||||
EEPROM_writeAnything(i,ver); // invalidate data first
|
||||
EEPROM_writeAnything(i,axis_steps_per_unit);
|
||||
EEPROM_writeAnything(i,max_feedrate);
|
||||
EEPROM_writeAnything(i,max_acceleration_units_per_sq_second);
|
||||
EEPROM_writeAnything(i,acceleration);
|
||||
EEPROM_writeAnything(i,retract_acceleration);
|
||||
EEPROM_writeAnything(i,minimumfeedrate);
|
||||
EEPROM_writeAnything(i,mintravelfeedrate);
|
||||
EEPROM_writeAnything(i,minsegmenttime);
|
||||
EEPROM_writeAnything(i,max_xy_jerk);
|
||||
EEPROM_writeAnything(i,max_z_jerk);
|
||||
EEPROM_writeAnything(i,max_e_jerk);
|
||||
EEPROM_writeAnything(i,add_homeing);
|
||||
#ifdef PIDTEMP
|
||||
EEPROM_writeAnything(i,Kp);
|
||||
EEPROM_writeAnything(i,Ki);
|
||||
EEPROM_writeAnything(i,Kd);
|
||||
EEPROM_writeAnything(i,Ki_Max);
|
||||
#else
|
||||
EEPROM_writeAnything(i,3000);
|
||||
EEPROM_writeAnything(i,0);
|
||||
EEPROM_writeAnything(i,0);
|
||||
#endif
|
||||
#if defined(UMFPUSUPPORT) && (UMFPUSUPPORT > -1)
|
||||
EEPROM_writeAnything(i,FPUEnabled);
|
||||
#endif
|
||||
char ver2[4]=EEPROM_VERSION;
|
||||
i=EEPROM_OFFSET;
|
||||
EEPROM_writeAnything(i,ver2); // validate data
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Settings Stored");
|
||||
#endif //EEPROM_SETTINGS
|
||||
}
|
||||
|
||||
|
||||
inline void EEPROM_printSettings()
|
||||
{ // if def=true, the default values will be used
|
||||
#ifdef EEPROM_SETTINGS
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Steps per unit:");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M92 X",axis_steps_per_unit[0]);
|
||||
SERIAL_ECHOPAIR(" Y",axis_steps_per_unit[1]);
|
||||
SERIAL_ECHOPAIR(" Z",axis_steps_per_unit[2]);
|
||||
SERIAL_ECHOPAIR(" E",axis_steps_per_unit[3]);
|
||||
SERIAL_ECHOLN("");
|
||||
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Maximum feedrates (mm/s):");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M203 X",max_feedrate[0]);
|
||||
SERIAL_ECHOPAIR(" Y",max_feedrate[1] );
|
||||
SERIAL_ECHOPAIR(" Z", max_feedrate[2] );
|
||||
SERIAL_ECHOPAIR(" E", max_feedrate[3]);
|
||||
SERIAL_ECHOLN("");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Maximum Acceleration (mm/s2):");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M201 X" ,max_acceleration_units_per_sq_second[0] );
|
||||
SERIAL_ECHOPAIR(" Y" , max_acceleration_units_per_sq_second[1] );
|
||||
SERIAL_ECHOPAIR(" Z" ,max_acceleration_units_per_sq_second[2] );
|
||||
SERIAL_ECHOPAIR(" E" ,max_acceleration_units_per_sq_second[3]);
|
||||
SERIAL_ECHOLN("");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Acceleration: S=acceleration, T=retract acceleration");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M204 S",acceleration );
|
||||
SERIAL_ECHOPAIR(" T" ,retract_acceleration);
|
||||
SERIAL_ECHOLN("");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M205 S",minimumfeedrate );
|
||||
SERIAL_ECHOPAIR(" T" ,mintravelfeedrate );
|
||||
SERIAL_ECHOPAIR(" B" ,minsegmenttime );
|
||||
SERIAL_ECHOPAIR(" X" ,max_xy_jerk );
|
||||
SERIAL_ECHOPAIR(" Z" ,max_z_jerk);
|
||||
SERIAL_ECHOPAIR(" E" ,max_e_jerk);
|
||||
SERIAL_ECHOLN("");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M206 X",add_homeing[0]);
|
||||
SERIAL_ECHOPAIR(" Y",add_homeing[1] );
|
||||
SERIAL_ECHOPAIR(" Z", add_homeing[2] );
|
||||
SERIAL_ECHOLN("");
|
||||
#ifdef PIDTEMP
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("PID settings:");
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPAIR(" M301 P",Kp);
|
||||
SERIAL_ECHOPAIR(" I" ,Ki/PID_dT);
|
||||
SERIAL_ECHOPAIR(" D" ,Kd*PID_dT);
|
||||
SERIAL_ECHOPAIR(" W" ,Ki_Max);
|
||||
SERIAL_ECHOLN("");
|
||||
#endif
|
||||
#if defined(UMFPUSUPPORT) && (UMFPUSUPPORT > -1)
|
||||
SERIAL_ECHOPAIR(" FPU Enabled" , FPUEnabled?" yes":" no");
|
||||
SERIAL_ECHOLN("");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline void EEPROM_RetrieveSettings(bool def=false)
|
||||
{ // if def=true, the default values will be used
|
||||
#ifdef EEPROM_SETTINGS
|
||||
int i=EEPROM_OFFSET;
|
||||
char stored_ver[4];
|
||||
char ver[4]=EEPROM_VERSION;
|
||||
EEPROM_readAnything(i,stored_ver); //read stored version
|
||||
// SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << stored_ver << "]");
|
||||
if ((!def)&&(strncmp(ver,stored_ver,3)==0))
|
||||
{ // version number match
|
||||
EEPROM_readAnything(i,axis_steps_per_unit);
|
||||
EEPROM_readAnything(i,max_feedrate);
|
||||
EEPROM_readAnything(i,max_acceleration_units_per_sq_second);
|
||||
EEPROM_readAnything(i,acceleration);
|
||||
EEPROM_readAnything(i,retract_acceleration);
|
||||
EEPROM_readAnything(i,minimumfeedrate);
|
||||
EEPROM_readAnything(i,mintravelfeedrate);
|
||||
EEPROM_readAnything(i,minsegmenttime);
|
||||
EEPROM_readAnything(i,max_xy_jerk);
|
||||
EEPROM_readAnything(i,max_z_jerk);
|
||||
EEPROM_readAnything(i,max_e_jerk);
|
||||
EEPROM_readAnything(i,add_homeing);
|
||||
#ifndef PIDTEMP
|
||||
float Kp,Ki,Kd;
|
||||
int Ki_Max;
|
||||
#endif
|
||||
EEPROM_readAnything(i,Kp);
|
||||
EEPROM_readAnything(i,Ki);
|
||||
EEPROM_readAnything(i,Kd);
|
||||
EEPROM_readAnything(i,Ki_Max);
|
||||
#if defined(UMFPUSUPPORT) && (UMFPUSUPPORT > -1)
|
||||
EEPROM_readAnything(i,FPUEnabled);
|
||||
#endif
|
||||
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM("Stored settings retreived:");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT;
|
||||
float tmp2[]=DEFAULT_MAX_FEEDRATE;
|
||||
long tmp3[]=DEFAULT_MAX_ACCELERATION;
|
||||
for (short i=0;i<4;i++)
|
||||
{
|
||||
axis_steps_per_unit[i]=tmp1[i];
|
||||
max_feedrate[i]=tmp2[i];
|
||||
max_acceleration_units_per_sq_second[i]=tmp3[i];
|
||||
}
|
||||
acceleration=DEFAULT_ACCELERATION;
|
||||
retract_acceleration=DEFAULT_RETRACT_ACCELERATION;
|
||||
minimumfeedrate=DEFAULT_MINIMUMFEEDRATE;
|
||||
minsegmenttime=DEFAULT_MINSEGMENTTIME;
|
||||
mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE;
|
||||
max_xy_jerk=DEFAULT_XYJERK;
|
||||
max_z_jerk=DEFAULT_ZJERK;
|
||||
max_e_jerk=DEFAULT_EJERK;
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLN("Using Default settings:");
|
||||
}
|
||||
#ifdef EEPROM_CHITCHAT
|
||||
EEPROM_printSettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
#include "FPUTransform.h"
|
||||
|
||||
#if defined(UMFPUSUPPORT) && (UMFPUSUPPORT > -1)
|
||||
|
||||
#include "MatrixMath.h"
|
||||
|
||||
float MasterTransform[4][4]; // this is the transform that describes how to move from
|
||||
// ideal coordinates to real world coords
|
||||
|
||||
// private functions
|
||||
void loadMatrix(float X4, float Y3, float Z1, float X2, float Y2, float Z2, float X3, float Z3, float Z4);
|
||||
void transformDestination(float &X, float &Y, float &Z);
|
||||
|
||||
bool FPUEnabled; // this is a bypass switch so that with one command the FPU can be
|
||||
// turned off
|
||||
|
||||
void loadMatrix(float X4, float Y1, float Z1, float X2, float Y2, float Z2, float X3, float Z3, float Z4)
|
||||
{
|
||||
float Xdiff = X4 - X3;
|
||||
serialPrintFloat(Xdiff);
|
||||
SERIAL_ECHOLN("");
|
||||
float Ydiff = Y2 - Y1;
|
||||
serialPrintFloat(Ydiff);
|
||||
SERIAL_ECHOLN("");
|
||||
//clockwise
|
||||
float ZdiffX = Z4 - Z3;
|
||||
serialPrintFloat(ZdiffX);
|
||||
SERIAL_ECHOLN("");
|
||||
//anti clockwise
|
||||
float ZdiffY = Z1 - Z2;
|
||||
serialPrintFloat(ZdiffY);
|
||||
SERIAL_ECHOLN("");
|
||||
|
||||
|
||||
//modified to take advantage of small angle trig.
|
||||
float Xtheta = ZdiffX / Xdiff;
|
||||
// serialPrintFloat(Xtheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
float Ytheta = ZdiffY / Ydiff;
|
||||
// serialPrintFloat(Ytheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
float cosxtheta = 1-(Xtheta*Xtheta)/2;
|
||||
// serialPrintFloat(cosxtheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
float sinxtheta = Xtheta;
|
||||
// serialPrintFloat(sinxtheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
float cosytheta = 1-(Ytheta*Ytheta)/2;
|
||||
// serialPrintFloat(cosytheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
float sinytheta = Ytheta;
|
||||
// serialPrintFloat(sinytheta);
|
||||
// SERIAL_ECHOLN("");
|
||||
|
||||
//these transforms are to set the origin for each rotation
|
||||
float TranslateX0[4][4] = {{1.0, 0.0, 0.0, -X3},
|
||||
{0.0, 1.0, 0.0, -Y1},
|
||||
{0.0, 0.0, 1.0, -Z3},
|
||||
{0.0, 0.0, 0.0, 1.0}};
|
||||
|
||||
float TranslateY0[4][4] = {{1.0, 0.0, 0.0, -X2},
|
||||
{0.0, 1.0, 0.0, -Y1},
|
||||
{0.0, 0.0, 1.0, -Z1},
|
||||
{0.0, 0.0, 0.0, 1.0}};
|
||||
|
||||
//rotate in Y using XZ
|
||||
float TransformY[4][4] = {{cosxtheta, 0.0, sinxtheta, 0.0},
|
||||
{ 0.0, 1.0, 0.0, 0.0},
|
||||
{-sinxtheta, 0.0, cosxtheta, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 1.0}};
|
||||
//rotate in X using YZ
|
||||
float TransformX[4][4] = {{ 1.0, 0.0, 0.0, 0.0},
|
||||
{ 0.0, cosytheta, sinytheta, 0.0},
|
||||
{ 0.0,sinytheta, cosytheta, 0.0},
|
||||
{ 0.0, 0.0, 0.0, 1.0}};
|
||||
|
||||
|
||||
// first translate point1 to 0 then rotate in Y then translate back
|
||||
float MatrixStage1[4][4];
|
||||
float MatrixStage2[4][4];
|
||||
//matrixMaths.MatrixMult((float*)TranslateY0, (float*)TransformX, 4, 4, 4, (float*)MatrixStage1);
|
||||
//matrixMaths.MatrixPrint((float*)MatrixStage1, 4, 4, "MatrixStage1");
|
||||
//TranslateY0[0][3] = -TranslateY0[0][3];
|
||||
//TranslateY0[1][3] = -TranslateY0[1][3];
|
||||
//TranslateY0[2][3] = -TranslateY0[2][3];
|
||||
//matrixMaths.MatrixPrint((float*)TranslateY0, 4, 4, "TranslateY0");
|
||||
//matrixMaths.MatrixMult((float*)MatrixStage1, (float*)TranslateY0, 4, 4, 4, (float*)MatrixStage2);
|
||||
//matrixMaths.MatrixPrint((float*)MatrixStage2, 4, 4, "MatrixStage2");
|
||||
//Now translate point3 to 0 and rotate in x before translating back
|
||||
float MatrixStage3[4][4];
|
||||
float MatrixStage4[4][4];
|
||||
//matrixMaths.MatrixMult((float*)MatrixStage2, (float*)TranslateX0, 4, 4, 4, (float*)MatrixStage3);
|
||||
//matrixMaths.MatrixPrint((float*)MatrixStage3, 4, 4, "MatrixStage3");
|
||||
//matrixMaths.MatrixMult((float*)MatrixStage3, (float*)TransformY, 4, 4, 4, (float*)MatrixStage4);
|
||||
matrixMaths.MatrixMult((float*)TransformX, (float*)TransformY, 4, 4, 4, (float*)MasterTransform);
|
||||
matrixMaths.MatrixPrint((float*)MatrixStage4, 4, 4, "MatrixStage4");
|
||||
//TranslateX0[0][3] = -TranslateX0[0][3];
|
||||
//TranslateX0[1][3] = -TranslateX0[1][3];
|
||||
//TranslateX0[2][3] = -TranslateX0[2][3];
|
||||
//matrixMaths.MatrixPrint((float*)TranslateX0, 4, 4, "TranslateX0");
|
||||
//matrixMaths.MatrixMult((float*)MatrixStage4, (float*)TranslateX0, 4, 4, 4, (float*)MasterTransform);
|
||||
//matrixMaths.MatrixPrint((float*)MasterTransform, 4, 4, "MasterTransform (pre-invert)");
|
||||
|
||||
// We now have a way to translate from real-world coordinates to idealised coortdinates,
|
||||
// but what we actually want is a way to transform from the idealised g-code coordinates
|
||||
// to real world coordinates.
|
||||
// This is simply the inverse.
|
||||
matrixMaths.MatrixInvert((float*)MasterTransform, 4);
|
||||
matrixMaths.MatrixPrint((float*)MasterTransform, 4, 4, "MasterTransform");
|
||||
}
|
||||
|
||||
void transformDestination(float &X, float &Y, float &Z)
|
||||
{
|
||||
float oldPoint[4][1]={{X}, {Y}, {Z}, {1.0}};
|
||||
float newPoint[1][4]={{0.0,0.0,0.0,0.0}};
|
||||
matrixMaths.MatrixMult((float*)MasterTransform, (float*)oldPoint, 4, 4, 1, (float*)newPoint);
|
||||
X=newPoint[0][0];
|
||||
Y=newPoint[0][1];
|
||||
Z=newPoint[0][2];
|
||||
}
|
||||
|
||||
void FPUTransform_init()
|
||||
{
|
||||
if (FPUEnabled == true)
|
||||
{
|
||||
// It is important to ensure that if the bed levelling routine has not been called the
|
||||
// printer behaves as if the real world and idealised world are one and the same
|
||||
matrixMaths.MatrixIdentity((float*)MasterTransform,4,4);
|
||||
SERIAL_ECHO("transform configured to identity");
|
||||
}
|
||||
else
|
||||
{
|
||||
SERIAL_ECHO("transform correction not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
void FPUEnable()
|
||||
{
|
||||
FPUEnabled = true;
|
||||
FPUTransform_init();
|
||||
}
|
||||
|
||||
void FPUReset()
|
||||
{
|
||||
FPUTransform_init();
|
||||
}
|
||||
|
||||
void FPUDisable()
|
||||
{
|
||||
FPUEnabled = false;
|
||||
}
|
||||
|
||||
void FPUTransform_determineBedOrientation()
|
||||
{
|
||||
int X3 = 15;
|
||||
float X4 = X_MAX_LENGTH - 20;
|
||||
float X2 = (X4 + X3) / 2;
|
||||
int Y1 = 15;
|
||||
float Y2 = Y_MAX_LENGTH - 5;
|
||||
float Z1;
|
||||
float Z2;
|
||||
float Z3;
|
||||
float Z4;
|
||||
|
||||
//get Z for X15 Y15, X15 Y(Y_MAX_LENGTH - 15) and X(X_MAX_LENGTH - 15) Y15
|
||||
Z3 = Probe_Bed(X3,Y1,PROBE_N);
|
||||
Z4 = Probe_Bed(X4,Y1,PROBE_N);
|
||||
Z1 = (Z3 + Z4) / 2;
|
||||
Z2 = Probe_Bed(X2,Y2,PROBE_N);
|
||||
if(FPUEnabled)
|
||||
{
|
||||
loadMatrix(X4, Y1, Z1, X2, Y2, Z2, X3, Z3, Z4);
|
||||
}
|
||||
}
|
||||
|
||||
void FPUTransform_transformDestination()
|
||||
{
|
||||
float XPoint = destination[X_AXIS]; // float variable
|
||||
float YPoint = destination[Y_AXIS]; // float variable
|
||||
float ZPoint = destination[Z_AXIS]; // float variable
|
||||
if(FPUEnabled)
|
||||
{
|
||||
transformDestination(XPoint, YPoint, ZPoint);
|
||||
}
|
||||
modified_destination[X_AXIS] = XPoint; // float variable
|
||||
modified_destination[Y_AXIS] = YPoint; // float variable
|
||||
modified_destination[Z_AXIS] = ZPoint; // float variable
|
||||
}
|
||||
|
||||
#endif //UMFPUSUPPORT
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __FPUTRANSFORM
|
||||
|
||||
#define __FPUTRANSFORM
|
||||
#include "Marlin.h"
|
||||
#include "z_probe.h"
|
||||
|
||||
#if defined(UMFPUSUPPORT) && (UMFPUSUPPORT > -1)
|
||||
extern bool FPUEnabled;
|
||||
void FPUTransform_init();
|
||||
void FPUEnable();
|
||||
void FPUReset();
|
||||
void FPUDisable();
|
||||
void FPUTransform_determineBedOrientation();
|
||||
void FPUTransform_transformDestination();
|
||||
|
||||
#else //no UMFPU SUPPORT
|
||||
FORCE_INLINE void FPUTransform_init() {};
|
||||
|
||||
#endif //UMFPUSUPPORT
|
||||
|
||||
#endif //__FPUTRANSFORM
|
||||
+84
-77
@@ -1,4 +1,4 @@
|
||||
# Marlin Arduino Project Makefile
|
||||
# Sprinter Arduino Project Makefile
|
||||
#
|
||||
# Makefile Based on:
|
||||
# Arduino 0011 Makefile
|
||||
@@ -23,7 +23,9 @@
|
||||
# 3. Set the line containing "MCU" to match your board's processor.
|
||||
# Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
|
||||
# or Diecimila have the atmega168. If you're using a LilyPad Arduino,
|
||||
# change F_CPU to 8000000.
|
||||
# change F_CPU to 8000000. If you are using Gen7 electronics, you
|
||||
# probably need to use 20000000. Either way, you must regenerate
|
||||
# the speed lookup table with create_speed_lookuptable.py.
|
||||
#
|
||||
# 4. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
@@ -32,30 +34,38 @@
|
||||
#
|
||||
# $Id$
|
||||
|
||||
TARGET = Marlin
|
||||
INSTALL_DIR = ../../Desktop/arduino-0018/
|
||||
UPLOAD_RATE = 38400
|
||||
AVRDUDE_PROGRAMMER = stk500v1
|
||||
PORT = /dev/ttyUSB0
|
||||
#MCU = atmega2560
|
||||
#For "old" Arduino Mega
|
||||
#MCU = atmega1280
|
||||
MCU = atmega1280
|
||||
#For Arduino Mega2560
|
||||
#MCU = atmega2560
|
||||
#For Sanguinololu
|
||||
MCU = atmega644p
|
||||
#MCU = atmega644p
|
||||
|
||||
#Arduino install directory
|
||||
INSTALL_DIR = ../../arduino-0022/
|
||||
|
||||
# Be sure to regenerate speed_lookuptable.h with create_speed_lookuptable.py
|
||||
# if you are setting this to something other than 16MHz
|
||||
F_CPU = 16000000
|
||||
|
||||
UPLOAD_RATE = 115200
|
||||
AVRDUDE_PROGRAMMER = arduino
|
||||
PORT = /dev/arduino
|
||||
|
||||
TARGET = $(notdir $(CURDIR))
|
||||
|
||||
|
||||
############################################################################
|
||||
# Below here nothing should be changed...
|
||||
|
||||
ARDUINO = $(INSTALL_DIR)/hardware/Sanguino/cores/arduino
|
||||
AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin
|
||||
SRC = $(ARDUINO)/pins_arduino.c wiring.c wiring_serial.c \
|
||||
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
|
||||
$(ARDUINO)/wiring_pulse.c \
|
||||
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
|
||||
CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \
|
||||
$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp
|
||||
ARDUINO = $(INSTALL_DIR)/hardware/arduino/cores/arduino
|
||||
AVR_TOOLS_PATH =
|
||||
SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
|
||||
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
|
||||
$(ARDUINO)/wiring_pulse.c \
|
||||
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
|
||||
CXXSRC = $(ARDUINO)/WMath.cpp $(ARDUINO)/WString.cpp\
|
||||
$(ARDUINO)/Print.cpp applet/Marlin.cpp MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp SdFatUtil.cpp SdFile.cpp SdVolume.cpp motion_control.cpp planner.cpp stepper.cpp temperature.cpp cardreader.cpp
|
||||
FORMAT = ihex
|
||||
|
||||
|
||||
@@ -84,12 +94,12 @@ CXXINCS = -I$(ARDUINO)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
#CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wunused-variable
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -w -ffunction-sections -fdata-sections -DARDUINO=22
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CEXTRA) $(CTUNING)
|
||||
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -Wall $(CEXTRA) $(CTUNING)
|
||||
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -Wall $(CEXTRA) $(CTUNING)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS = -lm
|
||||
|
||||
@@ -98,18 +108,18 @@ LDFLAGS = -lm
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex:i
|
||||
AVRDUDE_FLAGS = -D -C $(INSTALL_DIR)/hardware/tools/avrdude.conf \
|
||||
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE)
|
||||
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE)
|
||||
|
||||
# Program settings
|
||||
CC = $(AVR_TOOLS_PATH)/avr-gcc
|
||||
CXX = $(AVR_TOOLS_PATH)/avr-g++
|
||||
OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy
|
||||
OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump
|
||||
AR = $(AVR_TOOLS_PATH)/avr-ar
|
||||
SIZE = $(AVR_TOOLS_PATH)/avr-size
|
||||
NM = $(AVR_TOOLS_PATH)/avr-nm
|
||||
AVRDUDE = $(INSTALL_DIR)/hardware/tools/avrdude
|
||||
CC = $(AVR_TOOLS_PATH)avr-gcc
|
||||
CXX = $(AVR_TOOLS_PATH)avr-g++
|
||||
OBJCOPY = $(AVR_TOOLS_PATH)avr-objcopy
|
||||
OBJDUMP = $(AVR_TOOLS_PATH)avr-objdump
|
||||
AR = $(AVR_TOOLS_PATH)avr-ar
|
||||
SIZE = $(AVR_TOOLS_PATH)avr-size
|
||||
NM = $(AVR_TOOLS_PATH)avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
@@ -127,22 +137,25 @@ ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: applet_files_ez build sizeafter
|
||||
all: build sizeafter
|
||||
|
||||
build: elf hex
|
||||
|
||||
applet_files_ez: $(TARGET).pde
|
||||
# Here is the "preprocessing".
|
||||
# It creates a .cpp file based with the same name as the .pde file.
|
||||
# On top of the new .cpp file comes the WProgram.h header.
|
||||
# At the end there is a generic main() function attached.
|
||||
# Then the .cpp file will be compiled. Errors during compile will
|
||||
# refer to this new, automatically generated, file.
|
||||
# Not the original .pde file you actually edit...
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO)/main.cpp >> applet/$(TARGET).cpp
|
||||
applet/$(TARGET).cpp: $(TARGET).pde $(MAKEFILE)
|
||||
|
||||
applet/%.cpp: %.pde
|
||||
# Here is the "preprocessing".
|
||||
# It creates a .cpp file based with the same name as the .pde file.
|
||||
# On top of the new .cpp file comes the WProgram.h header.
|
||||
# At the end there is a generic main() function attached.
|
||||
# Then the .cpp file will be compiled. Errors during compile will
|
||||
# refer to this new, automatically generated, file.
|
||||
# Not the original .pde file you actually edit...
|
||||
@echo " WR $@"
|
||||
@test -d $(dir $@) || mkdir $(dir $@)
|
||||
@echo '#include "WProgram.h"' > $@
|
||||
@cat $< >> $@
|
||||
@cat $(ARDUINO)/main.cpp >> $@
|
||||
|
||||
elf: applet/$(TARGET).elf
|
||||
hex: applet/$(TARGET).hex
|
||||
@@ -152,7 +165,9 @@ sym: applet/$(TARGET).sym
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
stty hup < $(PORT); true
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
stty -hup < $(PORT); true
|
||||
|
||||
|
||||
# Display size of file.
|
||||
@@ -162,15 +177,15 @@ sizebefore:
|
||||
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi
|
||||
|
||||
sizeafter:
|
||||
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi
|
||||
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
@@ -182,13 +197,15 @@ extcoff: $(TARGET).elf
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym
|
||||
.PRECIOUS: .o
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
@echo " COPY $@"
|
||||
@$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
@@ -199,39 +216,29 @@ extcoff: $(TARGET).elf
|
||||
$(NM) -n $< > $@
|
||||
|
||||
# Link: create ELF output file from library.
|
||||
applet/$(TARGET).elf: $(TARGET).pde applet/core.a
|
||||
$(CC) $(ALL_CFLAGS) -Wl,--gc-sections -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp applet/core.a Configuration.h
|
||||
@echo " CXX $@"
|
||||
@$(CC) $(ALL_CXXFLAGS) -Wl,--gc-sections -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)
|
||||
|
||||
applet/core.a: $(OBJ)
|
||||
@for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done
|
||||
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o:
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o:
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
applet/core.a: $(OBJ) Configuration.h
|
||||
@for i in $(OBJ); do echo " AR $$i"; $(AR) rcs applet/core.a $$i; done
|
||||
|
||||
%.o: %.c Configuration.h $(MAKEFILE)
|
||||
@echo " CC $@"
|
||||
@$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
%.o: %.cpp Configuration.h $(MAKEFILE)
|
||||
@echo " CXX $@"
|
||||
@$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
|
||||
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/core.a \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
@echo " RM applet/*"
|
||||
@$(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
|
||||
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp applet/core.a \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
@echo " RMDIR applet/"
|
||||
@rmdir applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
|
||||
+179
-83
@@ -1,107 +1,203 @@
|
||||
// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
|
||||
// Licence: GPL
|
||||
#include <WProgram.h>
|
||||
|
||||
#ifndef MARLIN_H
|
||||
#define MARLIN_H
|
||||
|
||||
#define HardwareSerial_h // trick to disable the standard HWserial
|
||||
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
|
||||
#include "fastio.h"
|
||||
extern "C" void __cxa_pure_virtual();
|
||||
void __cxa_pure_virtual(){};
|
||||
#include "Configuration.h"
|
||||
#include "pins.h"
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#if defined(__AVR_ATmega644P__) || defined (__AVR_ATmega1284P__)
|
||||
#include "WProgram.h"
|
||||
#else
|
||||
#include "Arduino.h"
|
||||
#endif
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "MarlinSerial.h"
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
#include "WString.h"
|
||||
|
||||
#if MOTHERBOARD == 8 // Teensylu
|
||||
#define MYSERIAL Serial
|
||||
#else
|
||||
#define MYSERIAL MSerial
|
||||
#endif
|
||||
|
||||
//this is a unfinsihed attemp to removes a lot of warning messages, see:
|
||||
// http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=57011
|
||||
//typedef char prog_char PROGMEM;
|
||||
// //#define PSTR (s ) ((const PROGMEM char *)(s))
|
||||
// //# define MYPGM(s) (__extension__({static prog_char __c[] = (s); &__c[0];}))
|
||||
// //#define MYPGM(s) ((const prog_char *g PROGMEM=s))
|
||||
#define MYPGM(s) PSTR(s)
|
||||
//#define MYPGM(s) (__extension__({static char __c[] __attribute__((__progmem__)) = (s); &__c[0];})) //This is the normal behaviour
|
||||
//#define MYPGM(s) (__extension__({static prog_char __c[] = (s); &__c[0];})) //this does not work but hides the warnings
|
||||
|
||||
|
||||
#define SERIAL_PROTOCOL(x) MYSERIAL.print(x);
|
||||
#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y);
|
||||
#define SERIAL_PROTOCOLPGM(x) serialprintPGM(MYPGM(x));
|
||||
#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');}
|
||||
#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(MYPGM(x));MYSERIAL.write('\n');}
|
||||
|
||||
|
||||
const char errormagic[] PROGMEM ="Error:";
|
||||
const char echomagic[] PROGMEM ="echo:";
|
||||
#define SERIAL_ERROR_START serialprintPGM(errormagic);
|
||||
#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
|
||||
#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
|
||||
#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
|
||||
#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
|
||||
|
||||
#define SERIAL_ECHO_START serialprintPGM(echomagic);
|
||||
#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
|
||||
#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
|
||||
#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
|
||||
#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
|
||||
|
||||
#define SERIAL_ECHOPAIR(name,value) {SERIAL_ECHOPGM(name);SERIAL_ECHO(value);}
|
||||
|
||||
|
||||
//things to write to serial from Programmemory. saves 400 to 2k of RAM.
|
||||
#define SerialprintPGM(x) serialprintPGM(MYPGM(x))
|
||||
FORCE_INLINE void serialprintPGM(const char *str)
|
||||
{
|
||||
char ch=pgm_read_byte(str);
|
||||
while(ch)
|
||||
{
|
||||
MYSERIAL.write(ch);
|
||||
ch=pgm_read_byte(++str);
|
||||
}
|
||||
}
|
||||
|
||||
// printing floats to 3DP
|
||||
FORCE_INLINE void serialPrintFloat( float f){
|
||||
SERIAL_ECHO((int)f);
|
||||
SERIAL_ECHOPGM(".");
|
||||
int mantissa = (f - (int)f) * 1000;
|
||||
SERIAL_ECHO( abs(mantissa) );
|
||||
}
|
||||
|
||||
void get_command();
|
||||
void process_commands();
|
||||
|
||||
void manage_inactivity(byte debug);
|
||||
|
||||
void manage_heater();
|
||||
int temp2analogu(int celsius, const short table[][2], int numtemps);
|
||||
float analog2tempu(int raw, const short table[][2], int numtemps);
|
||||
#ifdef HEATER_USES_THERMISTOR
|
||||
#define HEATERSOURCE 1
|
||||
#endif
|
||||
#ifdef BED_USES_THERMISTOR
|
||||
#define BEDSOURCE 1
|
||||
#endif
|
||||
|
||||
#define temp2analogh( c ) temp2analogu((c),temptable,NUMTEMPS)
|
||||
#define analog2temp( c ) analog2tempu((c),temptable,NUMTEMPS)
|
||||
|
||||
#if X_ENABLE_PIN > -1
|
||||
#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
|
||||
#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON)
|
||||
#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
|
||||
#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON)
|
||||
#else
|
||||
#define enable_x() ;
|
||||
#define disable_x() ;
|
||||
#endif
|
||||
#if Y_ENABLE_PIN > -1
|
||||
#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
|
||||
#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON)
|
||||
#else
|
||||
#define enable_y() ;
|
||||
#define disable_y() ;
|
||||
#endif
|
||||
#if Z_ENABLE_PIN > -1
|
||||
#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
|
||||
#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON)
|
||||
#else
|
||||
#define enable_z() ;
|
||||
#define disable_z() ;
|
||||
#endif
|
||||
#if E_ENABLE_PIN > -1
|
||||
#define enable_e() WRITE(E_ENABLE_PIN, E_ENABLE_ON)
|
||||
#define disable_e() WRITE(E_ENABLE_PIN,!E_ENABLE_ON)
|
||||
#else
|
||||
#define enable_e() ;
|
||||
#define disable_e() ;
|
||||
#define enable_x() ;
|
||||
#define disable_x() ;
|
||||
#endif
|
||||
|
||||
#define X_AXIS 0
|
||||
#define Y_AXIS 1
|
||||
#define Z_AXIS 2
|
||||
#define E_AXIS 3
|
||||
#if Y_ENABLE_PIN > -1
|
||||
#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
|
||||
#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON)
|
||||
#else
|
||||
#define enable_y() ;
|
||||
#define disable_y() ;
|
||||
#endif
|
||||
|
||||
#if Z_ENABLE_PIN > -1
|
||||
#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
|
||||
#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON)
|
||||
#else
|
||||
#define enable_z() ;
|
||||
#define disable_z() ;
|
||||
#endif
|
||||
|
||||
#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
|
||||
#define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON)
|
||||
#define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON)
|
||||
#else
|
||||
#define enable_e0() /* nothing */
|
||||
#define disable_e0() /* nothing */
|
||||
#endif
|
||||
|
||||
#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
|
||||
#define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON)
|
||||
#define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON)
|
||||
#else
|
||||
#define enable_e1() /* nothing */
|
||||
#define disable_e1() /* nothing */
|
||||
#endif
|
||||
|
||||
#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
|
||||
#define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON)
|
||||
#define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON)
|
||||
#else
|
||||
#define enable_e2() /* nothing */
|
||||
#define disable_e2() /* nothing */
|
||||
#endif
|
||||
|
||||
|
||||
enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3};
|
||||
|
||||
|
||||
void FlushSerialRequestResend();
|
||||
void ClearToSend();
|
||||
|
||||
void get_coordinates();
|
||||
void prepare_move();
|
||||
void linear_move(unsigned long steps_remaining[]);
|
||||
void do_step(int axis);
|
||||
void kill(byte debug);
|
||||
void kill();
|
||||
void Stop();
|
||||
|
||||
// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in
|
||||
// the source g-code and may never actually be reached if acceleration management is active.
|
||||
typedef struct {
|
||||
// Fields used by the bresenham algorithm for tracing the line
|
||||
long steps_x, steps_y, steps_z, steps_e; // Step count along each axis
|
||||
long step_event_count; // The number of step events required to complete this block
|
||||
volatile long accelerate_until; // The index of the step event on which to stop acceleration
|
||||
volatile long decelerate_after; // The index of the step event on which to start decelerating
|
||||
volatile long acceleration_rate; // The acceleration rate used for acceleration calculation
|
||||
unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
|
||||
bool IsStopped();
|
||||
|
||||
long advance_rate;
|
||||
volatile long initial_advance;
|
||||
volatile long final_advance;
|
||||
float advance;
|
||||
void enquecommand(const char *cmd); //put an ascii command at the end of the current buffer.
|
||||
void prepare_arc_move(char isclockwise);
|
||||
|
||||
// Fields used by the motion planner to manage acceleration
|
||||
float speed_x, speed_y, speed_z, speed_e; // Nominal mm/minute for each axis
|
||||
float nominal_speed; // The nominal speed for this block in mm/min
|
||||
float millimeters; // The total travel of this block in mm
|
||||
float entry_speed;
|
||||
float acceleration; // acceleration mm/sec^2
|
||||
#ifndef CRITICAL_SECTION_START
|
||||
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
|
||||
#define CRITICAL_SECTION_END SREG = _sreg;
|
||||
#endif //CRITICAL_SECTION_START
|
||||
|
||||
// Settings for the trapezoid generator
|
||||
long nominal_rate; // The nominal step rate for this block in step_events/sec
|
||||
volatile long initial_rate; // The jerk-adjusted step rate at start of block
|
||||
volatile long final_rate; // The minimal rate at exit
|
||||
long acceleration_st; // acceleration steps/sec^2
|
||||
volatile char busy;
|
||||
} block_t;
|
||||
extern float homing_feedrate[];
|
||||
extern float fast_home_feedrate[];
|
||||
extern bool axis_relative_modes[];
|
||||
extern volatile int feedmultiply;
|
||||
extern int saved_feedmultiply;
|
||||
extern float current_position[NUM_AXIS] ;
|
||||
extern float add_homeing[3];
|
||||
extern unsigned char FanSpeed;
|
||||
|
||||
void check_axes_activity();
|
||||
void plan_init();
|
||||
void st_init();
|
||||
void tp_init();
|
||||
void plan_buffer_line(float x, float y, float z, float e, float feed_rate);
|
||||
void plan_set_position(float x, float y, float z, float e);
|
||||
void st_wake_up();
|
||||
void st_synchronize();
|
||||
extern float destination[NUM_AXIS];
|
||||
extern float modified_destination[NUM_AXIS];
|
||||
extern float offset[3];
|
||||
extern float feedrate, next_feedrate, saved_feedrate;
|
||||
|
||||
|
||||
// Handling multiple extruders pins
|
||||
extern uint8_t active_extruder;
|
||||
|
||||
#endif
|
||||
|
||||
+1243
-1645
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
HardwareSerial.cpp - Hardware serial library for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
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 23 November 2006 by David A. Mellis
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "MarlinSerial.h"
|
||||
|
||||
#if MOTHERBOARD != 8 // !teensylu
|
||||
// this next line disables the entire HardwareSerial.cpp,
|
||||
// this is so I can support Attiny series and any other chip without a uart
|
||||
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
ring_buffer rx_buffer = { { 0 }, 0, 0 };
|
||||
#endif
|
||||
|
||||
FORCE_INLINE void store_char(unsigned char c)
|
||||
{
|
||||
int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
|
||||
|
||||
// if we should be storing the received character into the location
|
||||
// just before the tail (meaning that the head would advance to the
|
||||
// current location of the tail), we're about to overflow the buffer
|
||||
// and so we don't write the character or advance the head.
|
||||
if (i != rx_buffer.tail) {
|
||||
rx_buffer.buffer[rx_buffer.head] = c;
|
||||
rx_buffer.head = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#elif defined(SIG_USART_RECV)
|
||||
#if defined(USART0_RX_vect)
|
||||
// fixed by Mark Sproul this is on the 644/644p
|
||||
//SIGNAL(SIG_USART_RECV)
|
||||
SIGNAL(USART0_RX_vect)
|
||||
{
|
||||
#if defined(UDR0)
|
||||
unsigned char c = UDR0;
|
||||
#elif defined(UDR)
|
||||
unsigned char c = UDR; // atmega8, atmega32
|
||||
#else
|
||||
#error UDR not defined
|
||||
#endif
|
||||
store_char(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constructors ////////////////////////////////////////////////////////////////
|
||||
|
||||
MarlinSerial::MarlinSerial()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
void MarlinSerial::begin(long baud)
|
||||
{
|
||||
uint16_t baud_setting;
|
||||
bool useU2X0 = 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) {
|
||||
useU2X0 = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (useU2X0) {
|
||||
UCSR0A = 1 << U2X0;
|
||||
baud_setting = (F_CPU / 4 / baud - 1) / 2;
|
||||
} else {
|
||||
UCSR0A = 0;
|
||||
baud_setting = (F_CPU / 8 / baud - 1) / 2;
|
||||
}
|
||||
|
||||
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
|
||||
UBRR0H = baud_setting >> 8;
|
||||
UBRR0L = baud_setting;
|
||||
|
||||
sbi(UCSR0B, RXEN0);
|
||||
sbi(UCSR0B, TXEN0);
|
||||
sbi(UCSR0B, RXCIE0);
|
||||
}
|
||||
|
||||
void MarlinSerial::end()
|
||||
{
|
||||
cbi(UCSR0B, RXEN0);
|
||||
cbi(UCSR0B, TXEN0);
|
||||
cbi(UCSR0B, RXCIE0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MarlinSerial::peek(void)
|
||||
{
|
||||
if (rx_buffer.head == rx_buffer.tail) {
|
||||
return -1;
|
||||
} else {
|
||||
return rx_buffer.buffer[rx_buffer.tail];
|
||||
}
|
||||
}
|
||||
|
||||
int MarlinSerial::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;
|
||||
} else {
|
||||
unsigned char c = rx_buffer.buffer[rx_buffer.tail];
|
||||
rx_buffer.tail = (unsigned int)(rx_buffer.tail + 1) % RX_BUFFER_SIZE;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
void MarlinSerial::flush()
|
||||
{
|
||||
// don't reverse this or there may be problems if the RX interrupt
|
||||
// occurs after reading the value of rx_buffer_head but before writing
|
||||
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||
// don't reverse this or there may be problems if the RX interrupt
|
||||
// occurs after reading the value of rx_buffer_head but before writing
|
||||
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||
// were full, not empty.
|
||||
rx_buffer.head = rx_buffer.tail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// imports from print.h
|
||||
|
||||
|
||||
|
||||
|
||||
void MarlinSerial::print(char c, int base)
|
||||
{
|
||||
print((long) c, base);
|
||||
}
|
||||
|
||||
void MarlinSerial::print(unsigned char b, int base)
|
||||
{
|
||||
print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
void MarlinSerial::print(int n, int base)
|
||||
{
|
||||
print((long) n, base);
|
||||
}
|
||||
|
||||
void MarlinSerial::print(unsigned int n, int base)
|
||||
{
|
||||
print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
void MarlinSerial::print(long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
write(n);
|
||||
} else if (base == 10) {
|
||||
if (n < 0) {
|
||||
print('-');
|
||||
n = -n;
|
||||
}
|
||||
printNumber(n, 10);
|
||||
} else {
|
||||
printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
void MarlinSerial::print(unsigned long n, int base)
|
||||
{
|
||||
if (base == 0) write(n);
|
||||
else printNumber(n, base);
|
||||
}
|
||||
|
||||
void MarlinSerial::print(double n, int digits)
|
||||
{
|
||||
printFloat(n, digits);
|
||||
}
|
||||
|
||||
void MarlinSerial::println(void)
|
||||
{
|
||||
print('\r');
|
||||
print('\n');
|
||||
}
|
||||
|
||||
void MarlinSerial::println(const String &s)
|
||||
{
|
||||
print(s);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(const char c[])
|
||||
{
|
||||
print(c);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(char c, int base)
|
||||
{
|
||||
print(c, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(unsigned char b, int base)
|
||||
{
|
||||
print(b, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(int n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(unsigned int n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(long n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(unsigned long n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void MarlinSerial::println(double n, int digits)
|
||||
{
|
||||
print(n, digits);
|
||||
println();
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
void MarlinSerial::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
unsigned long i = 0;
|
||||
|
||||
if (n == 0) {
|
||||
print('0');
|
||||
return;
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
buf[i++] = n % base;
|
||||
n /= base;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
print((char) (buf[i - 1] < 10 ?
|
||||
'0' + buf[i - 1] :
|
||||
'A' + buf[i - 1] - 10));
|
||||
}
|
||||
|
||||
void MarlinSerial::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
print('-');
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i)
|
||||
rounding /= 10.0;
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0)
|
||||
print(".");
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
remainder *= 10.0;
|
||||
int toPrint = int(remainder);
|
||||
print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
}
|
||||
// Preinstantiate Objects //////////////////////////////////////////////////////
|
||||
|
||||
|
||||
MarlinSerial MSerial;
|
||||
|
||||
#endif // whole file
|
||||
#endif //teensylu
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef MarlinSerial_h
|
||||
#define MarlinSerial_h
|
||||
#include "Marlin.h"
|
||||
|
||||
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
#define BYTE 0
|
||||
|
||||
|
||||
#if MOTHERBOARD != 8 // ! teensylu
|
||||
// Define constants and variables for buffering incoming serial data. We're
|
||||
// using a ring buffer (I think), in which rx_buffer_head is the index of the
|
||||
// location to which to write the next incoming character and rx_buffer_tail
|
||||
// is the index of the location from which to read.
|
||||
#define RX_BUFFER_SIZE 128
|
||||
|
||||
|
||||
struct ring_buffer
|
||||
{
|
||||
unsigned char buffer[RX_BUFFER_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
};
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
extern ring_buffer rx_buffer;
|
||||
#endif
|
||||
|
||||
class MarlinSerial //: public Stream
|
||||
{
|
||||
|
||||
public:
|
||||
MarlinSerial();
|
||||
void begin(long);
|
||||
void end();
|
||||
int peek(void);
|
||||
int read(void);
|
||||
void flush(void);
|
||||
|
||||
FORCE_INLINE int available(void)
|
||||
{
|
||||
return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
FORCE_INLINE void write(uint8_t c)
|
||||
{
|
||||
while (!((UCSR0A) & (1 << UDRE0)))
|
||||
;
|
||||
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE void checkRx(void)
|
||||
{
|
||||
if((UCSR0A & (1<<RXC0)) != 0) {
|
||||
unsigned char c = UDR0;
|
||||
int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
|
||||
|
||||
// if we should be storing the received character into the location
|
||||
// just before the tail (meaning that the head would advance to the
|
||||
// current location of the tail), we're about to overflow the buffer
|
||||
// and so we don't write the character or advance the head.
|
||||
if (i != rx_buffer.tail) {
|
||||
rx_buffer.buffer[rx_buffer.head] = c;
|
||||
rx_buffer.head = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void printNumber(unsigned long, uint8_t);
|
||||
void printFloat(double, uint8_t);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
FORCE_INLINE void write(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
write(*str++);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE void write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
while (size--)
|
||||
write(*buffer++);
|
||||
}
|
||||
|
||||
FORCE_INLINE void print(const String &s)
|
||||
{
|
||||
for (int i = 0; i < (int)s.length(); i++) {
|
||||
write(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void print(const char *str)
|
||||
{
|
||||
write(str);
|
||||
}
|
||||
void print(char, int = BYTE);
|
||||
void print(unsigned char, int = BYTE);
|
||||
void print(int, int = DEC);
|
||||
void print(unsigned int, int = DEC);
|
||||
void print(long, int = DEC);
|
||||
void print(unsigned long, int = DEC);
|
||||
void print(double, int = 2);
|
||||
|
||||
void println(const String &s);
|
||||
void println(const char[]);
|
||||
void println(char, int = BYTE);
|
||||
void println(unsigned char, int = BYTE);
|
||||
void println(int, int = DEC);
|
||||
void println(unsigned int, int = DEC);
|
||||
void println(long, int = DEC);
|
||||
void println(unsigned long, int = DEC);
|
||||
void println(double, int = 2);
|
||||
void println(void);
|
||||
};
|
||||
|
||||
extern MarlinSerial MSerial;
|
||||
#endif // ! teensylu
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* MatrixMath.cpp Library for MatrixMath
|
||||
*
|
||||
* Created by Charlie Matlack on 12/18/10.
|
||||
* Modified from code by RobH45345 on Arduino Forums, taken from unknown source.
|
||||
* MatrixMath.cpp
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "MatrixMath.h"
|
||||
|
||||
#define NR_END 1
|
||||
|
||||
MatrixMath::MatrixMath()
|
||||
{
|
||||
}
|
||||
|
||||
// Matrix Printing Routine
|
||||
// Uses tabs to separate numbers under assumption printed float width won't cause problems
|
||||
void MatrixMath::MatrixPrint(float* A, int m, int n, String label){
|
||||
// A = input matrix (m x n)
|
||||
int i,j;
|
||||
SERIAL_ECHOLN(' ');
|
||||
SERIAL_ECHOLN(label);
|
||||
for (i=0; i<m; i++){
|
||||
for (j=0;j<n;j++){
|
||||
serialPrintFloat(A[n*i+j]);
|
||||
SERIAL_ECHO("\t");
|
||||
}
|
||||
SERIAL_ECHOLN(' ');
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixMath::MatrixCopy(float* A, int n, int m, float* B)
|
||||
{
|
||||
int i, j, k;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
{
|
||||
B[n*i+j] = A[n*i+j];
|
||||
}
|
||||
}
|
||||
|
||||
//Matrix Multiplication Routine
|
||||
// C = A*B
|
||||
void MatrixMath::MatrixMult(float* A, float* B, int m, int p, int n, float* C)
|
||||
{
|
||||
// A = input matrix (m x p)
|
||||
// B = input matrix (p x n)
|
||||
// m = number of rows in A
|
||||
// p = number of columns in A = number of rows in B
|
||||
// n = number of columns in B
|
||||
// C = output matrix = A*B (m x n)
|
||||
int i, j, k;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
{
|
||||
C[n*i+j]=0;
|
||||
for (k=0;k<p;k++)
|
||||
C[n*i+j]= C[n*i+j]+A[p*i+k]*B[n*k+j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Matrix Addition Routine
|
||||
void MatrixMath::MatrixAdd(float* A, float* B, int m, int n, float* C)
|
||||
{
|
||||
// A = input matrix (m x n)
|
||||
// B = input matrix (m x n)
|
||||
// m = number of rows in A = number of rows in B
|
||||
// n = number of columns in A = number of columns in B
|
||||
// C = output matrix = A+B (m x n)
|
||||
int i, j;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
C[n*i+j]=A[n*i+j]+B[n*i+j];
|
||||
}
|
||||
|
||||
|
||||
//Matrix Subtraction Routine
|
||||
void MatrixMath::MatrixSubtract(float* A, float* B, int m, int n, float* C)
|
||||
{
|
||||
// A = input matrix (m x n)
|
||||
// B = input matrix (m x n)
|
||||
// m = number of rows in A = number of rows in B
|
||||
// n = number of columns in A = number of columns in B
|
||||
// C = output matrix = A-B (m x n)
|
||||
int i, j;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
C[n*i+j]=A[n*i+j]-B[n*i+j];
|
||||
}
|
||||
|
||||
|
||||
//Matrix Transpose Routine
|
||||
void MatrixMath::MatrixTranspose(float* A, int m, int n, float* C)
|
||||
{
|
||||
// A = input matrix (m x n)
|
||||
// m = number of rows in A
|
||||
// n = number of columns in A
|
||||
// C = output matrix = the transpose of A (n x m)
|
||||
int i, j;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
C[m*j+i]=A[n*i+j];
|
||||
}
|
||||
|
||||
|
||||
//Matrix Inversion Routine
|
||||
// * This function inverts a matrix based on the Gauss Jordan method.
|
||||
// * Specifically, it uses partial pivoting to improve numeric stability.
|
||||
// * The algorithm is drawn from those presented in
|
||||
// NUMERICAL RECIPES: The Art of Scientific Computing.
|
||||
// * The function returns 1 on success, 0 on failure.
|
||||
// * NOTE: The argument is ALSO the result matrix, meaning the input matrix is REPLACED
|
||||
int MatrixMath::MatrixInvert(float* A, int n)
|
||||
{
|
||||
// A = input matrix AND result matrix
|
||||
// n = number of rows = number of columns in A (n x n)
|
||||
int pivrow; // keeps track of current pivot row
|
||||
int k,i,j; // k: overall index along diagonal; i: row index; j: col index
|
||||
int pivrows[n]; // keeps track of rows swaps to undo at end
|
||||
float tmp; // used for finding max value and making column swaps
|
||||
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
// find pivot row, the row with biggest entry in current column
|
||||
tmp = 0;
|
||||
for (i = k; i < n; i++)
|
||||
{
|
||||
if (abs(A[i*n+k]) >= tmp) // 'Avoid using other functions inside abs()?'
|
||||
{
|
||||
tmp = abs(A[i*n+k]);
|
||||
pivrow = i;
|
||||
}
|
||||
}
|
||||
|
||||
// check for singular matrix
|
||||
if (A[pivrow*n+k] == 0.0f)
|
||||
{
|
||||
SERIAL_ECHOLNPGM("Inversion failed due to singular matrix");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Execute pivot (row swap) if needed
|
||||
if (pivrow != k)
|
||||
{
|
||||
// swap row k with pivrow
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
tmp = A[k*n+j];
|
||||
A[k*n+j] = A[pivrow*n+j];
|
||||
A[pivrow*n+j] = tmp;
|
||||
}
|
||||
}
|
||||
pivrows[k] = pivrow; // record row swap (even if no swap happened)
|
||||
|
||||
tmp = 1.0f/A[k*n+k]; // invert pivot element
|
||||
A[k*n+k] = 1.0f; // This element of input matrix becomes result matrix
|
||||
|
||||
// Perform row reduction (divide every element by pivot)
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
A[k*n+j] = A[k*n+j]*tmp;
|
||||
}
|
||||
|
||||
// Now eliminate all other entries in this column
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (i != k)
|
||||
{
|
||||
tmp = A[i*n+k];
|
||||
A[i*n+k] = 0.0f; // The other place where in matrix becomes result mat
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
A[i*n+j] = A[i*n+j] - A[k*n+j]*tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Done, now need to undo pivot row swaps by doing column swaps in reverse order
|
||||
for (k = n-1; k >= 0; k--)
|
||||
{
|
||||
if (pivrows[k] != k)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
tmp = A[i*n+k];
|
||||
A[i*n+k] = A[i*n+pivrows[k]];
|
||||
A[i*n+pivrows[k]] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MatrixMath::MatrixIdentity(float* A, int m, int n)
|
||||
{
|
||||
int i, j;
|
||||
for (i=0;i<m;i++)
|
||||
for(j=0;j<n;j++)
|
||||
A[n*i+j]=i==j?1:0;
|
||||
}
|
||||
|
||||
MatrixMath matrixMaths; //instance
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* MatrixMath.h Library for Matrix Math
|
||||
*
|
||||
* Created by Charlie Matlack on 12/18/10.
|
||||
* Modified from code by RobH45345 on Arduino Forums, taken from unknown source.
|
||||
*/
|
||||
|
||||
#ifndef MatrixMath_h
|
||||
#define MatrixMath_h
|
||||
|
||||
#include "Marlin.h"
|
||||
|
||||
class MatrixMath
|
||||
{
|
||||
public:
|
||||
MatrixMath();
|
||||
void MatrixPrint(float* A, int m, int n, String label);
|
||||
void MatrixCopy(float* A, int n, int m, float* B);
|
||||
void MatrixMult(float* A, float* B, int m, int p, int n, float* C);
|
||||
void MatrixAdd(float* A, float* B, int m, int n, float* C);
|
||||
void MatrixSubtract(float* A, float* B, int m, int n, float* C);
|
||||
void MatrixTranspose(float* A, int m, int n, float* C);
|
||||
int MatrixInvert(float* A, int n);
|
||||
void MatrixIdentity(float* A, int m, int n);
|
||||
};
|
||||
|
||||
extern MatrixMath matrixMaths;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
##############################################################
|
||||
|
||||
sanguino.name=Sanguino
|
||||
sanguino.upload.protocol=stk500
|
||||
sanguino.upload.maximum_size=63488
|
||||
sanguino.upload.speed=38400
|
||||
sanguino.bootloader.low_fuses=0xFF
|
||||
sanguino.bootloader.high_fuses=0xDC
|
||||
sanguino.bootloader.extended_fuses=0xFD
|
||||
sanguino.bootloader.path=atmega644p
|
||||
sanguino.bootloader.file=ATmegaBOOT_644P.hex
|
||||
sanguino.bootloader.unlock_bits=0x3F
|
||||
sanguino.bootloader.lock_bits=0x0F
|
||||
sanguino.build.mcu=atmega644p
|
||||
sanguino.build.f_cpu=16000000L
|
||||
sanguino.build.core=arduino
|
||||
@@ -0,0 +1,713 @@
|
||||
/**********************************************************/
|
||||
/* Serial Bootloader for Atmel megaAVR Controllers */
|
||||
/* */
|
||||
/* tested with ATmega644 and ATmega644P */
|
||||
/* should work with other mega's, see code for details */
|
||||
/* */
|
||||
/* ATmegaBOOT.c */
|
||||
/* */
|
||||
/* 20090131: Added 324P support from Alex Leone */
|
||||
/* Marius Kintel */
|
||||
/* 20080915: applied ADABoot mods for Sanguino 644P */
|
||||
/* Brian Riley */
|
||||
/* 20080711: hacked for Sanguino by Zach Smith */
|
||||
/* and Justin Day */
|
||||
/* 20070626: hacked for Arduino Diecimila (which auto- */
|
||||
/* resets when a USB connection is made to it) */
|
||||
/* by D. Mellis */
|
||||
/* 20060802: hacked for Arduino by D. Cuartielles */
|
||||
/* based on a previous hack by D. Mellis */
|
||||
/* and D. Cuartielles */
|
||||
/* */
|
||||
/* Monitor and debug functions were added to the original */
|
||||
/* code by Dr. Erik Lins, chip45.com. (See below) */
|
||||
/* */
|
||||
/* Thanks to Karl Pitrich for fixing a bootloader pin */
|
||||
/* problem and more informative LED blinking! */
|
||||
/* */
|
||||
/* For the latest version see: */
|
||||
/* http://www.chip45.com/ */
|
||||
/* */
|
||||
/* ------------------------------------------------------ */
|
||||
/* */
|
||||
/* based on stk500boot.c */
|
||||
/* Copyright (c) 2003, Jason P. Kyle */
|
||||
/* All rights reserved. */
|
||||
/* see avr1.org for original file and information */
|
||||
/* */
|
||||
/* This program 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 2 of the License, or */
|
||||
/* (at your option) any later version. */
|
||||
/* */
|
||||
/* This program 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 this program; if not, write */
|
||||
/* to the Free Software Foundation, Inc., */
|
||||
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
/* */
|
||||
/* Licence can be viewed at */
|
||||
/* http://www.fsf.org/licenses/gpl.txt */
|
||||
/* */
|
||||
/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
|
||||
/* m8515,m8535. ATmega161 has a very small boot block so */
|
||||
/* isn't supported. */
|
||||
/* */
|
||||
/* Tested with m168 */
|
||||
/**********************************************************/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
/* some includes */
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/boot.h>
|
||||
|
||||
#ifdef ADABOOT
|
||||
#define NUM_LED_FLASHES 3
|
||||
#define ADABOOT_VER 1
|
||||
#endif
|
||||
|
||||
|
||||
/* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */
|
||||
#define MAX_ERROR_COUNT 5
|
||||
|
||||
/* set the UART baud rate */
|
||||
/* 20080711: hack by Zach Hoeken */
|
||||
#define BAUD_RATE 38400
|
||||
|
||||
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
|
||||
/* never allow AVR Studio to do an update !!!! */
|
||||
#define HW_VER 0x02
|
||||
#define SW_MAJOR 0x01
|
||||
#define SW_MINOR 0x10
|
||||
|
||||
/* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */
|
||||
/* if monitor functions are included, LED goes on after monitor was entered */
|
||||
#define LED_DDR DDRB
|
||||
#define LED_PORT PORTB
|
||||
#define LED_PIN PINB
|
||||
#define LED PINB0
|
||||
|
||||
/* define various device id's */
|
||||
/* manufacturer byte is always the same */
|
||||
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
#define SIG2 0x96
|
||||
#define SIG3 0x0A
|
||||
#elif defined(__AVR_ATmega644__)
|
||||
#define SIG2 0x96
|
||||
#define SIG3 0x09
|
||||
#elif defined(__AVR_ATmega324P__)
|
||||
#define SIG2 0x95
|
||||
#define SIG3 0x08
|
||||
#endif
|
||||
#define PAGE_SIZE 0x080U //128 words
|
||||
#define PAGE_SIZE_BYTES 0x100U //256 bytes
|
||||
|
||||
/* function prototypes */
|
||||
void putch(char);
|
||||
char getch(void);
|
||||
void getNch(uint8_t);
|
||||
void byte_response(uint8_t);
|
||||
void nothing_response(void);
|
||||
char gethex(void);
|
||||
void puthex(char);
|
||||
void flash_led(uint8_t);
|
||||
|
||||
/* some variables */
|
||||
union address_union
|
||||
{
|
||||
uint16_t word;
|
||||
uint8_t byte[2];
|
||||
} address;
|
||||
|
||||
union length_union
|
||||
{
|
||||
uint16_t word;
|
||||
uint8_t byte[2];
|
||||
} length;
|
||||
|
||||
struct flags_struct
|
||||
{
|
||||
unsigned eeprom : 1;
|
||||
unsigned rampz : 1;
|
||||
} flags;
|
||||
|
||||
uint8_t buff[256];
|
||||
|
||||
uint8_t error_count = 0;
|
||||
uint8_t sreg;
|
||||
|
||||
void (*app_start)(void) = 0x0000;
|
||||
|
||||
/* main program starts here */
|
||||
int main(void)
|
||||
{
|
||||
uint8_t ch,ch2;
|
||||
uint16_t w;
|
||||
uint16_t i;
|
||||
|
||||
asm volatile("nop\n\t");
|
||||
|
||||
#ifdef ADABOOT // BBR/LF 10/8/2007 & 9/13/2008
|
||||
ch = MCUSR;
|
||||
MCUSR = 0;
|
||||
|
||||
WDTCSR |= _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = 0;
|
||||
|
||||
// Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.
|
||||
if (! (ch & _BV(EXTRF))) // if its a not an external reset...
|
||||
app_start(); // skip bootloader
|
||||
#endif
|
||||
|
||||
|
||||
//initialize our serial port.
|
||||
UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
|
||||
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
|
||||
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
|
||||
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
|
||||
|
||||
/* Enable internal pull-up resistor on pin D0 (RX), in order
|
||||
to supress line noise that prevents the bootloader from
|
||||
timing out (DAM: 20070509) */
|
||||
DDRD &= ~_BV(PIND0);
|
||||
PORTD |= _BV(PIND0);
|
||||
|
||||
/* set LED pin as output */
|
||||
LED_DDR |= _BV(LED);
|
||||
|
||||
/* flash onboard LED to signal entering of bootloader */
|
||||
/* ADABOOT will do two series of flashes. first 4 - signifying ADABOOT */
|
||||
/* then a pause and another flash series signifying ADABOOT sub-version */
|
||||
|
||||
|
||||
flash_led(NUM_LED_FLASHES);
|
||||
|
||||
#ifdef ADABOOT
|
||||
flash_led(ADABOOT_VER); // BBR 9/13/2008
|
||||
#endif
|
||||
|
||||
/* forever loop */
|
||||
for (;;)
|
||||
{
|
||||
/* get character from UART */
|
||||
ch = getch();
|
||||
|
||||
/* A bunch of if...else if... gives smaller code than switch...case ! */
|
||||
|
||||
/* Hello is anyone home ? */
|
||||
if(ch=='0')
|
||||
nothing_response();
|
||||
|
||||
|
||||
/* Request programmer ID */
|
||||
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
|
||||
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
|
||||
else if(ch=='1')
|
||||
{
|
||||
if (getch() == ' ')
|
||||
{
|
||||
putch(0x14);
|
||||
putch('A');
|
||||
putch('V');
|
||||
putch('R');
|
||||
putch(' ');
|
||||
putch('I');
|
||||
putch('S');
|
||||
putch('P');
|
||||
putch(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
|
||||
else if(ch=='@')
|
||||
{
|
||||
ch2 = getch();
|
||||
if (ch2 > 0x85)
|
||||
getch();
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* AVR ISP/STK500 board requests */
|
||||
else if(ch=='A')
|
||||
{
|
||||
ch2 = getch();
|
||||
if(ch2 == 0x80)
|
||||
byte_response(HW_VER); // Hardware version
|
||||
else if(ch2==0x81)
|
||||
byte_response(SW_MAJOR); // Software major version
|
||||
else if(ch2==0x82)
|
||||
byte_response(SW_MINOR); // Software minor version
|
||||
else if(ch2==0x98)
|
||||
byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
|
||||
else
|
||||
byte_response(0x00); // Covers various unnecessary responses we don't care about
|
||||
}
|
||||
|
||||
|
||||
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
|
||||
else if(ch=='B')
|
||||
{
|
||||
getNch(20);
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* Parallel programming stuff DON'T CARE */
|
||||
else if(ch=='E')
|
||||
{
|
||||
getNch(5);
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* Enter programming mode */
|
||||
else if(ch=='P')
|
||||
{
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* Leave programming mode */
|
||||
else if(ch=='Q')
|
||||
{
|
||||
nothing_response();
|
||||
#ifdef ADABOOT
|
||||
// autoreset via watchdog (sneaky!) BBR/LF 9/13/2008
|
||||
WDTCSR = _BV(WDE);
|
||||
while (1); // 16 ms
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Erase device, don't care as we will erase one page at a time anyway. */
|
||||
else if(ch=='R')
|
||||
{
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* Set address, little endian. EEPROM in bytes, FLASH in words */
|
||||
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
|
||||
/* This might explain why little endian was used here, big endian used everywhere else. */
|
||||
else if(ch=='U')
|
||||
{
|
||||
address.byte[0] = getch();
|
||||
address.byte[1] = getch();
|
||||
nothing_response();
|
||||
}
|
||||
|
||||
|
||||
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
|
||||
else if(ch=='V')
|
||||
{
|
||||
getNch(4);
|
||||
byte_response(0x00);
|
||||
}
|
||||
|
||||
|
||||
/* Write memory, length is big endian and is in bytes */
|
||||
else if(ch=='d')
|
||||
{
|
||||
length.byte[1] = getch();
|
||||
length.byte[0] = getch();
|
||||
|
||||
flags.eeprom = 0;
|
||||
if (getch() == 'E')
|
||||
flags.eeprom = 1;
|
||||
|
||||
for (i=0; i<PAGE_SIZE; i++)
|
||||
buff[i] = 0;
|
||||
|
||||
for (w = 0; w < length.word; w++)
|
||||
{
|
||||
// Store data in buffer, can't keep up with serial data stream whilst programming pages
|
||||
buff[w] = getch();
|
||||
}
|
||||
|
||||
if (getch() == ' ')
|
||||
{
|
||||
if (flags.eeprom)
|
||||
{
|
||||
//Write to EEPROM one byte at a time
|
||||
for(w=0;w<length.word;w++)
|
||||
{
|
||||
while(EECR & (1<<EEPE));
|
||||
|
||||
EEAR = (uint16_t)(void *)address.word;
|
||||
EEDR = buff[w];
|
||||
EECR |= (1<<EEMPE);
|
||||
EECR |= (1<<EEPE);
|
||||
|
||||
address.word++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//address * 2 -> byte location
|
||||
address.word = address.word << 1;
|
||||
|
||||
//Even up an odd number of bytes
|
||||
if ((length.byte[0] & 0x01))
|
||||
length.word++;
|
||||
|
||||
// HACKME: EEPE used to be EEWE
|
||||
//Wait for previous EEPROM writes to complete
|
||||
//while(bit_is_set(EECR,EEPE));
|
||||
while(EECR & (1<<EEPE));
|
||||
|
||||
asm volatile(
|
||||
"clr r17 \n\t" //page_word_count
|
||||
"lds r30,address \n\t" //Address of FLASH location (in bytes)
|
||||
"lds r31,address+1 \n\t"
|
||||
"ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
|
||||
"ldi r29,hi8(buff) \n\t"
|
||||
"lds r24,length \n\t" //Length of data to be written (in bytes)
|
||||
"lds r25,length+1 \n\t"
|
||||
"length_loop: \n\t" //Main loop, repeat for number of words in block
|
||||
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
|
||||
"brne no_page_erase \n\t"
|
||||
"wait_spm1: \n\t"
|
||||
"lds r16,%0 \n\t" //Wait for previous spm to complete
|
||||
"andi r16,1 \n\t"
|
||||
"cpi r16,1 \n\t"
|
||||
"breq wait_spm1 \n\t"
|
||||
"ldi r16,0x03 \n\t" //Erase page pointed to by Z
|
||||
"sts %0,r16 \n\t"
|
||||
"spm \n\t"
|
||||
"wait_spm2: \n\t"
|
||||
"lds r16,%0 \n\t" //Wait for previous spm to complete
|
||||
"andi r16,1 \n\t"
|
||||
"cpi r16,1 \n\t"
|
||||
"breq wait_spm2 \n\t"
|
||||
|
||||
"ldi r16,0x11 \n\t" //Re-enable RWW section
|
||||
"sts %0,r16 \n\t"
|
||||
"spm \n\t"
|
||||
"no_page_erase: \n\t"
|
||||
"ld r0,Y+ \n\t" //Write 2 bytes into page buffer
|
||||
"ld r1,Y+ \n\t"
|
||||
|
||||
"wait_spm3: \n\t"
|
||||
"lds r16,%0 \n\t" //Wait for previous spm to complete
|
||||
"andi r16,1 \n\t"
|
||||
"cpi r16,1 \n\t"
|
||||
"breq wait_spm3 \n\t"
|
||||
"ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
|
||||
"sts %0,r16 \n\t"
|
||||
"spm \n\t"
|
||||
|
||||
"inc r17 \n\t" //page_word_count++
|
||||
"cpi r17,%1 \n\t"
|
||||
"brlo same_page \n\t" //Still same page in FLASH
|
||||
"write_page: \n\t"
|
||||
"clr r17 \n\t" //New page, write current one first
|
||||
"wait_spm4: \n\t"
|
||||
"lds r16,%0 \n\t" //Wait for previous spm to complete
|
||||
"andi r16,1 \n\t"
|
||||
"cpi r16,1 \n\t"
|
||||
"breq wait_spm4 \n\t"
|
||||
"ldi r16,0x05 \n\t" //Write page pointed to by Z
|
||||
"sts %0,r16 \n\t"
|
||||
"spm \n\t"
|
||||
"wait_spm5: \n\t"
|
||||
"lds r16,%0 \n\t" //Wait for previous spm to complete
|
||||
"andi r16,1 \n\t"
|
||||
"cpi r16,1 \n\t"
|
||||
"breq wait_spm5 \n\t"
|
||||
"ldi r16,0x11 \n\t" //Re-enable RWW section
|
||||
"sts %0,r16 \n\t"
|
||||
"spm \n\t"
|
||||
"same_page: \n\t"
|
||||
"adiw r30,2 \n\t" //Next word in FLASH
|
||||
"sbiw r24,2 \n\t" //length-2
|
||||
"breq final_write \n\t" //Finished
|
||||
"rjmp length_loop \n\t"
|
||||
"final_write: \n\t"
|
||||
"cpi r17,0 \n\t"
|
||||
"breq block_done \n\t"
|
||||
"adiw r24,2 \n\t" //length+2, fool above check on length after short page write
|
||||
"rjmp write_page \n\t"
|
||||
"block_done: \n\t"
|
||||
"clr __zero_reg__ \n\t" //restore zero register
|
||||
: "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"
|
||||
|
||||
);
|
||||
}
|
||||
putch(0x14);
|
||||
putch(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
}
|
||||
}
|
||||
|
||||
/* Read memory block mode, length is big endian. */
|
||||
else if(ch=='t')
|
||||
{
|
||||
length.byte[1] = getch();
|
||||
length.byte[0] = getch();
|
||||
|
||||
if (getch() == 'E')
|
||||
flags.eeprom = 1;
|
||||
else
|
||||
{
|
||||
flags.eeprom = 0;
|
||||
address.word = address.word << 1; // address * 2 -> byte location
|
||||
}
|
||||
|
||||
// Command terminator
|
||||
if (getch() == ' ')
|
||||
{
|
||||
putch(0x14);
|
||||
for (w=0; w<length.word; w++)
|
||||
{
|
||||
// Can handle odd and even lengths okay
|
||||
if (flags.eeprom)
|
||||
{
|
||||
// Byte access EEPROM read
|
||||
while(EECR & (1<<EEPE));
|
||||
EEAR = (uint16_t)(void *)address.word;
|
||||
EECR |= (1<<EERE);
|
||||
putch(EEDR);
|
||||
|
||||
address.word++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!flags.rampz)
|
||||
putch(pgm_read_byte_near(address.word));
|
||||
|
||||
address.word++;
|
||||
}
|
||||
}
|
||||
putch(0x10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get device signature bytes */
|
||||
else if(ch=='u')
|
||||
{
|
||||
if (getch() == ' ')
|
||||
{
|
||||
putch(0x14);
|
||||
putch(SIG1);
|
||||
putch(SIG2);
|
||||
putch(SIG3);
|
||||
putch(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read oscillator calibration byte */
|
||||
else if(ch=='v')
|
||||
byte_response(0x00);
|
||||
|
||||
else if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
|
||||
}
|
||||
/* end of forever loop */
|
||||
}
|
||||
|
||||
|
||||
char gethex(void)
|
||||
{
|
||||
char ah,al;
|
||||
|
||||
ah = getch();
|
||||
putch(ah);
|
||||
al = getch();
|
||||
putch(al);
|
||||
|
||||
if(ah >= 'a')
|
||||
ah = ah - 'a' + 0x0a;
|
||||
else if(ah >= '0')
|
||||
ah -= '0';
|
||||
if(al >= 'a')
|
||||
al = al - 'a' + 0x0a;
|
||||
else if(al >= '0')
|
||||
al -= '0';
|
||||
|
||||
return (ah << 4) + al;
|
||||
}
|
||||
|
||||
|
||||
void puthex(char ch)
|
||||
{
|
||||
char ah,al;
|
||||
|
||||
ah = (ch & 0xf0) >> 4;
|
||||
if(ah >= 0x0a)
|
||||
ah = ah - 0x0a + 'a';
|
||||
else
|
||||
ah += '0';
|
||||
|
||||
al = (ch & 0x0f);
|
||||
if(al >= 0x0a)
|
||||
al = al - 0x0a + 'a';
|
||||
else
|
||||
al += '0';
|
||||
|
||||
putch(ah);
|
||||
putch(al);
|
||||
}
|
||||
|
||||
|
||||
void putch(char ch)
|
||||
{
|
||||
while (!(UCSR0A & _BV(UDRE0)));
|
||||
UDR0 = ch;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char getch(void)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
|
||||
#ifdef ADABOOT
|
||||
LED_PORT &= ~_BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
|
||||
#endif
|
||||
|
||||
while(!(UCSR0A & _BV(RXC0)))
|
||||
{
|
||||
/* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/
|
||||
/* HACKME:: here is a good place to count times*/
|
||||
count++;
|
||||
if (count > MAX_TIME_COUNT)
|
||||
app_start();
|
||||
}
|
||||
|
||||
#ifdef ADABOOT
|
||||
LED_PORT |= _BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
|
||||
#endif
|
||||
|
||||
return UDR0;
|
||||
}
|
||||
|
||||
|
||||
void getNch(uint8_t count)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i=0;i<count;i++)
|
||||
{
|
||||
while(!(UCSR0A & _BV(RXC0)));
|
||||
UDR0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void byte_response(uint8_t val)
|
||||
{
|
||||
if (getch() == ' ')
|
||||
{
|
||||
putch(0x14);
|
||||
putch(val);
|
||||
putch(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nothing_response(void)
|
||||
{
|
||||
if (getch() == ' ')
|
||||
{
|
||||
putch(0x14);
|
||||
putch(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++error_count == MAX_ERROR_COUNT)
|
||||
app_start();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ADABOOT
|
||||
|
||||
void flash_led(uint8_t count)
|
||||
{
|
||||
/* flash onboard LED count times to signal entering of bootloader */
|
||||
/* l needs to be volatile or the delay loops below might get */
|
||||
/* optimized away if compiling with optimizations (DAM). */
|
||||
|
||||
volatile uint32_t l;
|
||||
|
||||
if (count == 0) {
|
||||
count = ADABOOT;
|
||||
}
|
||||
|
||||
|
||||
int8_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
LED_PORT |= _BV(LED); // LED on
|
||||
for(l = 0; l < (F_CPU / 1000); ++l); // delay NGvalue was 1000 for both loops - BBR
|
||||
LED_PORT &= ~_BV(LED); // LED off
|
||||
for(l = 0; l < (F_CPU / 250); ++l); // delay asymmteric for ADA BOOT BBR
|
||||
}
|
||||
|
||||
for(l = 0; l < (F_CPU / 100); ++l); // pause ADA BOOT BBR
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void flash_led(uint8_t count)
|
||||
{
|
||||
/* flash onboard LED three times to signal entering of bootloader */
|
||||
/* l needs to be volatile or the delay loops below might get
|
||||
optimized away if compiling with optimizations (DAM). */
|
||||
volatile uint32_t l;
|
||||
|
||||
if (count == 0) {
|
||||
count = 3;
|
||||
}
|
||||
|
||||
int8_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
LED_PORT |= _BV(LED);
|
||||
for(l = 0; l < (F_CPU / 1000); ++l);
|
||||
LED_PORT &= ~_BV(LED);
|
||||
for(l = 0; l < (F_CPU / 1000); ++l);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* end of file ATmegaBOOT.c */
|
||||
@@ -0,0 +1,121 @@
|
||||
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
|
||||
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
|
||||
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
|
||||
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
|
||||
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
|
||||
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
|
||||
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
|
||||
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
|
||||
:10F88000CFEFD8E0DEBFCDBF11E0A0E0B1E0E6E60B
|
||||
:10F89000FFEF02C005900D92A030B107D9F712E03A
|
||||
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
|
||||
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
|
||||
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
|
||||
:10F8D00009F481E020E0482F55274115510509F42E
|
||||
:10F8E0003DC0289A19821A821B821C820BC0898112
|
||||
:10F8F0009A81AB81BC810196A11DB11D89839A8338
|
||||
:10F90000AB83BC8389819A81AB81BC8180589E4343
|
||||
:10F91000A040B04060F3289819821A821B821C8292
|
||||
:10F920000BC089819A81AB81BC810196A11DB11D5B
|
||||
:10F9300089839A83AB83BC8389819A81AB81BC81A3
|
||||
:10F9400080509A4FA040B04060F32F5F822F9927DC
|
||||
:10F9500087FD9095841795070CF4C3CF19821A82FE
|
||||
:10F960001B821C8289819A81AB81BC818050914726
|
||||
:10F97000A240B040A0F489819A81AB81BC810196FC
|
||||
:10F98000A11DB11D89839A83AB83BC8389819A8130
|
||||
:10F99000AB81BC8180509147A240B04060F3249677
|
||||
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
|
||||
:10F9B000EF92FF920F931F93EE24FF248701289864
|
||||
:10F9C0008091C00087FD17C00894E11CF11C011D47
|
||||
:10F9D000111D81E0E81689E0F8068DE3080780E054
|
||||
:10F9E000180770F3E0910001F091010109958091F1
|
||||
:10F9F000C00087FFE9CF289A8091C600992787FD2C
|
||||
:10FA000090951F910F91FF90EF900895982F8091FE
|
||||
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
|
||||
:10FA2000803271F0809102018F5F809302018530F6
|
||||
:10FA300009F00895E0910001F09101010995089500
|
||||
:10FA400084E10E94067D80E10E94067D0895CF93A7
|
||||
:10FA5000C82F0E94D87C803241F0809102018F5FD4
|
||||
:10FA600080930201853081F40AC084E10E94067D02
|
||||
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
|
||||
:10FA80000001F09101010995CF910895282F90E090
|
||||
:10FA900007C08091C0008823E4F78091C6009F5F73
|
||||
:10FAA0009217B8F30895CFEFD8E0DEBFCDBF0000C6
|
||||
:10FAB00094B714BE809160008861809360001092BA
|
||||
:10FAC000600091FF74C189E18093C4001092C50069
|
||||
:10FAD00088E18093C10086E08093C2005098589AD4
|
||||
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
|
||||
:10FAF000D87C8033B9F18133C1F1803409F456C028
|
||||
:10FB0000813409F45CC0823409F46EC0853409F490
|
||||
:10FB100071C0803539F1813509F4F3C0823511F1B6
|
||||
:10FB2000853509F4D3C0863509F4CBC0843609F491
|
||||
:10FB300065C0843709F4EBC0853709F4D2C0863735
|
||||
:10FB400009F44AC0809102018F5F809302018530E1
|
||||
:10FB500071F6E0910001F091010109950E94D87CB5
|
||||
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
|
||||
:10FB7000803241F784E10E94067D81E40E94067D87
|
||||
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
|
||||
:10FB9000067D89E40E94067D83E50E94067D80E55E
|
||||
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
|
||||
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
|
||||
:10FBC000D87C803809F407C1813809F400C1823833
|
||||
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
|
||||
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
|
||||
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
|
||||
:10FC0000809306020E94D87C8093050280910802AE
|
||||
:10FC10008E7F809308020E94D87C853409F44BC003
|
||||
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
|
||||
:10FC3000C0E0D0E0809105029091060218161906E6
|
||||
:10FC400078F405E011E00E94D87CF80181938F01DF
|
||||
:10FC500021968091050290910602C817D90798F362
|
||||
:10FC60000E94D87C803209F06DCF8091080280FF1D
|
||||
:10FC7000B6C0C0E0D0E02091050230910602121615
|
||||
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
|
||||
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
|
||||
:10FCA00031962196C217D30798F3F0930401E0939D
|
||||
:10FCB000030184E175CF809108028160809308027E
|
||||
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
|
||||
:10FCD000809303010E94D87C809304010E940E7DD2
|
||||
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
|
||||
:10FCF000067D8EE10E94067D85E90E94067D88E0F2
|
||||
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
|
||||
:10FD1000D87C809306020E94D87C809305020E94C2
|
||||
:10FD2000D87C853409F449C0809108028E7F809385
|
||||
:10FD300008028091030190910401880F991F90930C
|
||||
:10FD40000401809303010E94D87C803209F0CFCE59
|
||||
:10FD500084E10E94067DC0E0D0E020910502309150
|
||||
:10FD600006021216130608F01DCFE0910301F09170
|
||||
:10FD700004018091080280FF96C0F999FECFF2BD80
|
||||
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
|
||||
:10FD900004013196F0930401E093030120910502E0
|
||||
:10FDA000309106022196C217D30718F3FBCEE091DB
|
||||
:10FDB0000001F0910101099586CE809108028160D1
|
||||
:10FDC00080930802C0CF80E10E94277D90CE81E021
|
||||
:10FDD0000E94277D8CCE82E00E94277D88CE809174
|
||||
:10FDE000030190910401880F991F9093040180935F
|
||||
:10FDF00003018091050280FF09C080910502909166
|
||||
:10FE0000060201969093060280930502F999FECFAF
|
||||
:10FE10001127E0910301F0910401C5E0D1E0809148
|
||||
:10FE2000050290910602103091F400915700017084
|
||||
:10FE30000130D9F303E000935700E8950091570093
|
||||
:10FE400001700130D9F301E100935700E895099062
|
||||
:10FE500019900091570001700130D9F301E000932F
|
||||
:10FE60005700E8951395103898F011270091570026
|
||||
:10FE700001700130D9F305E000935700E895009137
|
||||
:10FE8000570001700130D9F301E100935700E89564
|
||||
:10FE90003296029709F0C7CF103011F00296E5CFE5
|
||||
:10FEA000112484E17DCE869580FF06C03196F093C3
|
||||
:10FEB0000401E093030176CF84910E94067D209196
|
||||
:10FEC000050230910602E0910301F0910401EECFAA
|
||||
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
|
||||
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
|
||||
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
|
||||
:10FF000010330CF01053C295C07FC10F8C2F99276E
|
||||
:10FF100087FD9095CF911F910895CF93282F992712
|
||||
:10FF200087FD9095807F907095958795959587959D
|
||||
:10FF300095958795959587958A303CF0895AC22F7B
|
||||
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
|
||||
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
|
||||
:06FF6000CF910895FFCFD0
|
||||
:040000030000F80001
|
||||
:00000001FF
|
||||
@@ -0,0 +1,120 @@
|
||||
:10F800000C94387C0C94557C0C94557C0C94557C51
|
||||
:10F810000C94557C0C94557C0C94557C0C94557C24
|
||||
:10F820000C94557C0C94557C0C94557C0C94557C14
|
||||
:10F830000C94557C0C94557C0C94557C0C94557C04
|
||||
:10F840000C94557C0C94557C0C94557C0C94557CF4
|
||||
:10F850000C94557C0C94557C0C94557C0C94557CE4
|
||||
:10F860000C94557C0C94557C0C94557C0C94557CD4
|
||||
:10F8700011241FBECFEFD0E1DEBFCDBF11E0A0E06D
|
||||
:10F88000B1E0EAE5FFEF02C005900D92A030B107AC
|
||||
:10F89000D9F712E0A0E0B1E001C01D92A930B10794
|
||||
:10F8A000E1F70E944D7D0C94AC7F0C94007CCF93CB
|
||||
:10F8B000DF93CDB7DEB724970FB6F894DEBF0FBE47
|
||||
:10F8C000CDBF882309F481E020E0482F552741155A
|
||||
:10F8D000510509F43DC0289A19821A821B821C82A4
|
||||
:10F8E0000BC089819A81AB81BC810196A11DB11D9C
|
||||
:10F8F00089839A83AB83BC8389819A81AB81BC81E4
|
||||
:10F9000080589E43A040B04060F3289819821A8224
|
||||
:10F910001B821C820BC089819A81AB81BC810196BC
|
||||
:10F92000A11DB11D89839A83AB83BC8389819A8190
|
||||
:10F93000AB81BC8180509A4FA040B04060F32F5FF4
|
||||
:10F94000822F992787FD9095841795070CF4C3CFD4
|
||||
:10F9500019821A821B821C8289819A81AB81BC81A7
|
||||
:10F9600080509147A240B040A0F489819A81AB8138
|
||||
:10F97000BC810196A11DB11D89839A83AB83BC8391
|
||||
:10F9800089819A81AB81BC8180509147A240B0406F
|
||||
:10F9900060F324960FB6F894DEBF0FBECDBFDF91A3
|
||||
:10F9A000CF910895EF92FF920F931F93EE24FF24BF
|
||||
:10F9B000870128988091C00087FD17C00894E11C3A
|
||||
:10F9C000F11C011D111D81E0E81689E0F8068DE3A8
|
||||
:10F9D000080780E0180770F3E0910001F091010141
|
||||
:10F9E00009958091C00087FFE9CF289A8091C600D1
|
||||
:10F9F000992787FD90951F910F91FF90EF900895A3
|
||||
:10FA0000982F8091C00085FFFCCF9093C600089589
|
||||
:10FA10000E94D27C803271F0809102018F5F8093CE
|
||||
:10FA20000201853009F00895E0910001F091010193
|
||||
:10FA30000995089584E10E94007D80E10E94007D87
|
||||
:10FA40000895CF93C82F0E94D27C803241F08091DC
|
||||
:10FA500002018F5F80930201853081F40AC084E146
|
||||
:10FA60000E94007D8C2F0E94007D80E10E94007D1D
|
||||
:10FA700005C0E0910001F09101010995CF91089531
|
||||
:10FA8000282F90E007C08091C0008823E4F7809180
|
||||
:10FA9000C6009F5F9217B8F30895CFEFD0E1DEBFA5
|
||||
:10FAA000CDBF000094B714BE809160008861809340
|
||||
:10FAB00060001092600091FF74C189E18093C400DE
|
||||
:10FAC0001092C50088E18093C10086E08093C20057
|
||||
:10FAD0005098589A209A83E00E94577C81E00E94B7
|
||||
:10FAE000577C0E94D27C8033B9F18133C1F18034DC
|
||||
:10FAF00009F456C0813409F45CC0823409F46EC044
|
||||
:10FB0000853409F471C0803539F1813509F4F3C0C9
|
||||
:10FB1000823511F1853509F4D3C0863509F4CBC09F
|
||||
:10FB2000843609F465C0843709F4EBC0853709F4DD
|
||||
:10FB3000D2C0863709F44AC0809102018F5F80935A
|
||||
:10FB40000201853071F6E0910001F0910101099503
|
||||
:10FB50000E94D27C803349F60E94087DC2CF0E9469
|
||||
:10FB6000D27CC82F803241F784E10E94007D81E47D
|
||||
:10FB70000E94007D86E50E94007D82E50E94007D56
|
||||
:10FB80008C2F0E94007D89E40E94007D83E50E9405
|
||||
:10FB9000007D80E50E94007D80E10E94007DA1CF74
|
||||
:10FBA0000E94D27C8638C0F20E94D27C0E94087DDE
|
||||
:10FBB00098CF0E94D27C803809F407C1813809F4BB
|
||||
:10FBC00000C1823809F4F9C0883921F080E00E9430
|
||||
:10FBD000217D87CF83E00E94217D83CF84E10E9435
|
||||
:10FBE000407D0E94087D7DCF85E00E94407DF9CF59
|
||||
:10FBF0000E94D27C809306020E94D27C80930502F0
|
||||
:10FC0000809108028E7F809308020E94D27C853406
|
||||
:10FC100009F44BC0E5E0F1E0119281E0E438F80727
|
||||
:10FC2000D9F3D0F3C0E0D0E08091050290910602B4
|
||||
:10FC30001816190678F405E011E00E94D27CF8014C
|
||||
:10FC400081938F0121968091050290910602C81739
|
||||
:10FC5000D90798F30E94D27C803209F06DCF809151
|
||||
:10FC6000080280FFB6C0C0E0D0E0209105023091CC
|
||||
:10FC7000060212161306B8F4E0910301F091040194
|
||||
:10FC8000A5E0B1E0F999FECFF2BDE1BD8D9180BD57
|
||||
:10FC9000FA9AF99A31962196C217D30798F3F093FE
|
||||
:10FCA0000401E093030184E175CF80910802816033
|
||||
:10FCB00080930802AFCF84E00E94407D80E087CF30
|
||||
:10FCC0000E94D27C809303010E94D27C8093040125
|
||||
:10FCD0000E94087D06CF0E94D27C803209F02CCF92
|
||||
:10FCE00084E10E94007D8EE10E94007D86E90E94F1
|
||||
:10FCF000007D89E04FCF0E94087D88E080936000FE
|
||||
:10FD0000FFCF0E94D27C809306020E94D27C809317
|
||||
:10FD100005020E94D27C853409F449C08091080212
|
||||
:10FD20008E7F809308028091030190910401880FD7
|
||||
:10FD3000991F90930401809303010E94D27C80322A
|
||||
:10FD400009F0CFCE84E10E94007DC0E0D0E0209198
|
||||
:10FD50000502309106021216130608F01DCFE0913D
|
||||
:10FD60000301F09104018091080280FF96C0F99987
|
||||
:10FD7000FECFF2BDE1BDF89A80B50E94007DE09112
|
||||
:10FD80000301F09104013196F0930401E093030123
|
||||
:10FD900020910502309106022196C217D30718F36D
|
||||
:10FDA000FBCEE0910001F0910101099586CE809192
|
||||
:10FDB0000802816080930802C0CF80E10E94217D0B
|
||||
:10FDC00090CE81E00E94217D8CCE82E00E94217D38
|
||||
:10FDD00088CE8091030190910401880F991F909320
|
||||
:10FDE0000401809303018091050280FF09C0809186
|
||||
:10FDF00005029091060201969093060280930502F7
|
||||
:10FE0000F999FECF1127E0910301F0910401C5E0BB
|
||||
:10FE1000D1E08091050290910602103091F400919A
|
||||
:10FE2000570001700130D9F303E000935700E895C3
|
||||
:10FE30000091570001700130D9F301E100935700A0
|
||||
:10FE4000E895099019900091570001700130D9F39D
|
||||
:10FE500001E000935700E8951395103898F01127AA
|
||||
:10FE60000091570001700130D9F305E0009357006D
|
||||
:10FE7000E8950091570001700130D9F301E100933A
|
||||
:10FE80005700E8953296029709F0C7CF103011F06D
|
||||
:10FE90000296E5CF112484E17DCE869580FF06C0D1
|
||||
:10FEA0003196F0930401E093030176CF84910E9490
|
||||
:10FEB000007D2091050230910602E0910301F0914E
|
||||
:10FEC0000401EECF1F93CF930E94D27CC82F0E94D3
|
||||
:10FED000007D0E94D27C182F0E94007DC1362CF03C
|
||||
:10FEE000C75511363CF0175508C0C033D4F3C05382
|
||||
:10FEF0001136CCF710330CF01053C295C07FC10FF0
|
||||
:10FF00008C2F992787FD9095CF911F910895CF93BE
|
||||
:10FF1000282F992787FD9095807F907095958795DC
|
||||
:10FF20009595879595958795959587958A303CF019
|
||||
:10FF3000895AC22FCF70CA303CF0C95A06C0805DC2
|
||||
:10FF4000C22FCF70CA30CCF7C05D0E94007D8C2FCD
|
||||
:0AFF50000E94007DCF910895FFCFBD
|
||||
:040000030000F80001
|
||||
:00000001FF
|
||||
@@ -0,0 +1,121 @@
|
||||
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
|
||||
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
|
||||
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
|
||||
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
|
||||
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
|
||||
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
|
||||
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
|
||||
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
|
||||
:10F88000CFEFD0E1DEBFCDBF11E0A0E0B1E0E6E612
|
||||
:10F89000FFEF02C005900D92A030B107D9F712E03A
|
||||
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
|
||||
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
|
||||
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
|
||||
:10F8D00009F481E020E0482F55274115510509F42E
|
||||
:10F8E0003DC0289A19821A821B821C820BC0898112
|
||||
:10F8F0009A81AB81BC810196A11DB11D89839A8338
|
||||
:10F90000AB83BC8389819A81AB81BC8180589E4343
|
||||
:10F91000A040B04060F3289819821A821B821C8292
|
||||
:10F920000BC089819A81AB81BC810196A11DB11D5B
|
||||
:10F9300089839A83AB83BC8389819A81AB81BC81A3
|
||||
:10F9400080509A4FA040B04060F32F5F822F9927DC
|
||||
:10F9500087FD9095841795070CF4C3CF19821A82FE
|
||||
:10F960001B821C8289819A81AB81BC818050914726
|
||||
:10F97000A240B040A0F489819A81AB81BC810196FC
|
||||
:10F98000A11DB11D89839A83AB83BC8389819A8130
|
||||
:10F99000AB81BC8180509147A240B04060F3249677
|
||||
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
|
||||
:10F9B000EF92FF920F931F93EE24FF248701289864
|
||||
:10F9C0008091C00087FD17C00894E11CF11C011D47
|
||||
:10F9D000111D81E0E81689E0F8068DE3080780E054
|
||||
:10F9E000180770F3E0910001F091010109958091F1
|
||||
:10F9F000C00087FFE9CF289A8091C600992787FD2C
|
||||
:10FA000090951F910F91FF90EF900895982F8091FE
|
||||
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
|
||||
:10FA2000803271F0809102018F5F809302018530F6
|
||||
:10FA300009F00895E0910001F09101010995089500
|
||||
:10FA400084E10E94067D80E10E94067D0895CF93A7
|
||||
:10FA5000C82F0E94D87C803241F0809102018F5FD4
|
||||
:10FA600080930201853081F40AC084E10E94067D02
|
||||
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
|
||||
:10FA80000001F09101010995CF910895282F90E090
|
||||
:10FA900007C08091C0008823E4F78091C6009F5F73
|
||||
:10FAA0009217B8F30895CFEFD0E1DEBFCDBF0000CD
|
||||
:10FAB00094B714BE809160008861809360001092BA
|
||||
:10FAC000600091FF74C189E18093C4001092C50069
|
||||
:10FAD00088E18093C10086E08093C2005098589AD4
|
||||
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
|
||||
:10FAF000D87C8033B9F18133C1F1803409F456C028
|
||||
:10FB0000813409F45CC0823409F46EC0853409F490
|
||||
:10FB100071C0803539F1813509F4F3C0823511F1B6
|
||||
:10FB2000853509F4D3C0863509F4CBC0843609F491
|
||||
:10FB300065C0843709F4EBC0853709F4D2C0863735
|
||||
:10FB400009F44AC0809102018F5F809302018530E1
|
||||
:10FB500071F6E0910001F091010109950E94D87CB5
|
||||
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
|
||||
:10FB7000803241F784E10E94067D81E40E94067D87
|
||||
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
|
||||
:10FB9000067D89E40E94067D83E50E94067D80E55E
|
||||
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
|
||||
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
|
||||
:10FBC000D87C803809F407C1813809F400C1823833
|
||||
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
|
||||
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
|
||||
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
|
||||
:10FC0000809306020E94D87C8093050280910802AE
|
||||
:10FC10008E7F809308020E94D87C853409F44BC003
|
||||
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
|
||||
:10FC3000C0E0D0E0809105029091060218161906E6
|
||||
:10FC400078F405E011E00E94D87CF80181938F01DF
|
||||
:10FC500021968091050290910602C817D90798F362
|
||||
:10FC60000E94D87C803209F06DCF8091080280FF1D
|
||||
:10FC7000B6C0C0E0D0E02091050230910602121615
|
||||
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
|
||||
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
|
||||
:10FCA00031962196C217D30798F3F0930401E0939D
|
||||
:10FCB000030184E175CF809108028160809308027E
|
||||
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
|
||||
:10FCD000809303010E94D87C809304010E940E7DD2
|
||||
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
|
||||
:10FCF000067D8EE10E94067D86E90E94067D8AE0EF
|
||||
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
|
||||
:10FD1000D87C809306020E94D87C809305020E94C2
|
||||
:10FD2000D87C853409F449C0809108028E7F809385
|
||||
:10FD300008028091030190910401880F991F90930C
|
||||
:10FD40000401809303010E94D87C803209F0CFCE59
|
||||
:10FD500084E10E94067DC0E0D0E020910502309150
|
||||
:10FD600006021216130608F01DCFE0910301F09170
|
||||
:10FD700004018091080280FF96C0F999FECFF2BD80
|
||||
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
|
||||
:10FD900004013196F0930401E093030120910502E0
|
||||
:10FDA000309106022196C217D30718F3FBCEE091DB
|
||||
:10FDB0000001F0910101099586CE809108028160D1
|
||||
:10FDC00080930802C0CF80E10E94277D90CE81E021
|
||||
:10FDD0000E94277D8CCE82E00E94277D88CE809174
|
||||
:10FDE000030190910401880F991F9093040180935F
|
||||
:10FDF00003018091050280FF09C080910502909166
|
||||
:10FE0000060201969093060280930502F999FECFAF
|
||||
:10FE10001127E0910301F0910401C5E0D1E0809148
|
||||
:10FE2000050290910602103091F400915700017084
|
||||
:10FE30000130D9F303E000935700E8950091570093
|
||||
:10FE400001700130D9F301E100935700E895099062
|
||||
:10FE500019900091570001700130D9F301E000932F
|
||||
:10FE60005700E8951395103898F011270091570026
|
||||
:10FE700001700130D9F305E000935700E895009137
|
||||
:10FE8000570001700130D9F301E100935700E89564
|
||||
:10FE90003296029709F0C7CF103011F00296E5CFE5
|
||||
:10FEA000112484E17DCE869580FF06C03196F093C3
|
||||
:10FEB0000401E093030176CF84910E94067D209196
|
||||
:10FEC000050230910602E0910301F0910401EECFAA
|
||||
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
|
||||
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
|
||||
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
|
||||
:10FF000010330CF01053C295C07FC10F8C2F99276E
|
||||
:10FF100087FD9095CF911F910895CF93282F992712
|
||||
:10FF200087FD9095807F907095958795959587959D
|
||||
:10FF300095958795959587958A303CF0895AC22F7B
|
||||
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
|
||||
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
|
||||
:06FF6000CF910895FFCFD0
|
||||
:040000030000F80001
|
||||
:00000001FF
|
||||
@@ -0,0 +1,56 @@
|
||||
# Makefile for ATmegaBOOT
|
||||
# E.Lins, 18.7.2005
|
||||
# $Id$
|
||||
|
||||
|
||||
# program name should not be changed...
|
||||
PROGRAM = ATmegaBOOT_644P
|
||||
|
||||
# enter the target CPU frequency
|
||||
AVR_FREQ = 16000000L
|
||||
|
||||
MCU_TARGET = atmega644p
|
||||
LDSECTION = --section-start=.text=0xF800
|
||||
|
||||
OBJ = $(PROGRAM).o
|
||||
OPTIMIZE = -O2
|
||||
|
||||
DEFS =
|
||||
LIBS =
|
||||
|
||||
CC = avr-gcc
|
||||
|
||||
|
||||
# Override is only needed by avr-lib build system.
|
||||
|
||||
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||
override LDFLAGS = -Wl,$(LDSECTION)
|
||||
#override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
|
||||
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
|
||||
all: CFLAGS += '-DMAX_TIME_COUNT=8000000L>>1' -DADABOOT
|
||||
all: $(PROGRAM).hex
|
||||
|
||||
$(PROGRAM).hex: $(PROGRAM).elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
$(PROGRAM).elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
$(OBJ): ATmegaBOOT.c
|
||||
avr-gcc $(CFLAGS) $(LDFLAGS) -c -g -O2 -Wall -mmcu=$(MCU_TARGET) ATmegaBOOT.c -o $(PROGRAM).o
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.srec: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O srec $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Note: This bootloader support ATmega644, ATmega644P and ATmega324P.
|
||||
To build, set PROGRAM and MCU_TARGET in the Makefile according to your target device.
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
wiring.h - Partial implementation of the Wiring API for the ATmega8.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef Wiring_h
|
||||
#define Wiring_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <stdlib.h>
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
|
||||
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
void digitalWrite(uint8_t, uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(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 setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
HardwareSerial.cpp - Hardware serial library for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
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 23 November 2006 by David A. Mellis
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "wiring.h"
|
||||
#include "wiring_private.h"
|
||||
|
||||
// this next line disables the entire HardwareSerial.cpp,
|
||||
// this is so I can support Attiny series and any other chip without a uart
|
||||
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
|
||||
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
// Define constants and variables for buffering incoming serial data. We're
|
||||
// using a ring buffer (I think), in which rx_buffer_head is the index of the
|
||||
// location to which to write the next incoming character and rx_buffer_tail
|
||||
// is the index of the location from which to read.
|
||||
#define RX_BUFFER_SIZE 128
|
||||
|
||||
struct ring_buffer
|
||||
{
|
||||
unsigned char buffer[RX_BUFFER_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
};
|
||||
|
||||
ring_buffer rx_buffer = { { 0 }, 0, 0 };
|
||||
|
||||
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
|
||||
{
|
||||
int i = (unsigned int)(rx_buffer->head + 1) & (RX_BUFFER_SIZE -1);
|
||||
|
||||
// if we should be storing the received character into the location
|
||||
// just before the tail (meaning that the head would advance to the
|
||||
// current location of the tail), we're about to overflow the buffer
|
||||
// and so we don't write the character or advance the head.
|
||||
if (i != rx_buffer->tail) {
|
||||
rx_buffer->buffer[rx_buffer->head] = c;
|
||||
rx_buffer->head = i;
|
||||
}
|
||||
}
|
||||
|
||||
// fixed by Mark Sproul this is on the 644/644p
|
||||
//SIGNAL(SIG_USART_RECV)
|
||||
SIGNAL(USART0_RX_vect)
|
||||
{
|
||||
unsigned char c = UDR0;
|
||||
store_char(c, &rx_buffer);
|
||||
}
|
||||
|
||||
|
||||
// Constructors ////////////////////////////////////////////////////////////////
|
||||
|
||||
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
|
||||
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
|
||||
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
|
||||
volatile uint8_t *udr,
|
||||
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
|
||||
{
|
||||
_rx_buffer = rx_buffer;
|
||||
_ubrrh = ubrrh;
|
||||
_ubrrl = ubrrl;
|
||||
_ucsra = ucsra;
|
||||
_ucsrb = ucsrb;
|
||||
_udr = udr;
|
||||
_rxen = rxen;
|
||||
_txen = txen;
|
||||
_rxcie = rxcie;
|
||||
_udre = udre;
|
||||
_u2x = u2x;
|
||||
}
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
void HardwareSerial::begin(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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
|
||||
*_ubrrh = baud_setting >> 8;
|
||||
*_ubrrl = baud_setting;
|
||||
|
||||
sbi(*_ucsrb, _rxen);
|
||||
sbi(*_ucsrb, _txen);
|
||||
sbi(*_ucsrb, _rxcie);
|
||||
}
|
||||
|
||||
void HardwareSerial::end()
|
||||
{
|
||||
cbi(*_ucsrb, _rxen);
|
||||
cbi(*_ucsrb, _txen);
|
||||
cbi(*_ucsrb, _rxcie);
|
||||
}
|
||||
|
||||
int HardwareSerial::available(void)
|
||||
{
|
||||
return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) & (RX_BUFFER_SIZE-1);
|
||||
}
|
||||
|
||||
int HardwareSerial::peek(void)
|
||||
{
|
||||
if (_rx_buffer->head == _rx_buffer->tail) {
|
||||
return -1;
|
||||
} else {
|
||||
return _rx_buffer->buffer[_rx_buffer->tail];
|
||||
}
|
||||
}
|
||||
|
||||
int HardwareSerial::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;
|
||||
} else {
|
||||
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
|
||||
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) & (RX_BUFFER_SIZE-1);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareSerial::flush()
|
||||
{
|
||||
// don't reverse this or there may be problems if the RX interrupt
|
||||
// occurs after reading the value of rx_buffer_head but before writing
|
||||
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||
// don't reverse this or there may be problems if the RX interrupt
|
||||
// occurs after reading the value of rx_buffer_head but before writing
|
||||
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||
// were full, not empty.
|
||||
_rx_buffer->head = _rx_buffer->tail;
|
||||
}
|
||||
|
||||
void HardwareSerial::write(uint8_t c)
|
||||
{
|
||||
while (!((*_ucsra) & (1 << _udre)))
|
||||
;
|
||||
|
||||
*_udr = c;
|
||||
}
|
||||
|
||||
// Preinstantiate Objects //////////////////////////////////////////////////////
|
||||
HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
|
||||
|
||||
#endif // whole file
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef HardwareSerial_h
|
||||
#define HardwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
struct ring_buffer;
|
||||
|
||||
class HardwareSerial : public Stream
|
||||
{
|
||||
private:
|
||||
ring_buffer *_rx_buffer;
|
||||
volatile uint8_t *_ubrrh;
|
||||
volatile uint8_t *_ubrrl;
|
||||
volatile uint8_t *_ucsra;
|
||||
volatile uint8_t *_ucsrb;
|
||||
volatile uint8_t *_udr;
|
||||
uint8_t _rxen;
|
||||
uint8_t _txen;
|
||||
uint8_t _rxcie;
|
||||
uint8_t _udre;
|
||||
uint8_t _u2x;
|
||||
public:
|
||||
HardwareSerial(ring_buffer *rx_buffer,
|
||||
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
|
||||
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
|
||||
volatile uint8_t *udr,
|
||||
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
|
||||
void begin(long);
|
||||
void end();
|
||||
virtual int available(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual void write(uint8_t);
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
};
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
extern HardwareSerial Serial;
|
||||
#elif defined(USBCON)
|
||||
#include "usb_api.h"
|
||||
#endif
|
||||
#if defined(UBRR1H)
|
||||
extern HardwareSerial Serial1;
|
||||
#endif
|
||||
#if defined(UBRR2H)
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#if defined(UBRR3H)
|
||||
extern HardwareSerial Serial3;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Print.cpp - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. 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 23 November 2006 by David A. Mellis
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "wiring.h"
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
/* default implementation: may be overridden */
|
||||
void Print::write(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
write(*str++);
|
||||
}
|
||||
|
||||
/* default implementation: may be overridden */
|
||||
void Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
while (size--)
|
||||
write(*buffer++);
|
||||
}
|
||||
|
||||
void Print::print(const String &s)
|
||||
{
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
write(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Print::print(const char str[])
|
||||
{
|
||||
write(str);
|
||||
}
|
||||
|
||||
void Print::print(char c, int base)
|
||||
{
|
||||
print((long) c, base);
|
||||
}
|
||||
|
||||
void Print::print(unsigned char b, int base)
|
||||
{
|
||||
print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
void Print::print(int n, int base)
|
||||
{
|
||||
print((long) n, base);
|
||||
}
|
||||
|
||||
void Print::print(unsigned int n, int base)
|
||||
{
|
||||
print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
void Print::print(long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
write(n);
|
||||
} else if (base == 10) {
|
||||
if (n < 0) {
|
||||
print('-');
|
||||
n = -n;
|
||||
}
|
||||
printNumber(n, 10);
|
||||
} else {
|
||||
printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
void Print::print(unsigned long n, int base)
|
||||
{
|
||||
if (base == 0) write(n);
|
||||
else printNumber(n, base);
|
||||
}
|
||||
|
||||
void Print::print(double n, int digits)
|
||||
{
|
||||
printFloat(n, digits);
|
||||
}
|
||||
|
||||
void Print::println(void)
|
||||
{
|
||||
print('\r');
|
||||
print('\n');
|
||||
}
|
||||
|
||||
void Print::println(const String &s)
|
||||
{
|
||||
print(s);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(const char c[])
|
||||
{
|
||||
print(c);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(char c, int base)
|
||||
{
|
||||
print(c, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(unsigned char b, int base)
|
||||
{
|
||||
print(b, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(int n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(unsigned int n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(long n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(unsigned long n, int base)
|
||||
{
|
||||
print(n, base);
|
||||
println();
|
||||
}
|
||||
|
||||
void Print::println(double n, int digits)
|
||||
{
|
||||
print(n, digits);
|
||||
println();
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
void Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
unsigned long i = 0;
|
||||
|
||||
if (n == 0) {
|
||||
print('0');
|
||||
return;
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
buf[i++] = n % base;
|
||||
n /= base;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
print((char) (buf[i - 1] < 10 ?
|
||||
'0' + buf[i - 1] :
|
||||
'A' + buf[i - 1] - 10));
|
||||
}
|
||||
|
||||
void Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
print('-');
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i)
|
||||
rounding /= 10.0;
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0)
|
||||
print(".");
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
remainder *= 10.0;
|
||||
int toPrint = int(remainder);
|
||||
print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Print.h - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. 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
|
||||
*/
|
||||
|
||||
#ifndef Print_h
|
||||
#define Print_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h> // for size_t
|
||||
|
||||
#include "WString.h"
|
||||
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
#define BYTE 0
|
||||
|
||||
class Print
|
||||
{
|
||||
private:
|
||||
void printNumber(unsigned long, uint8_t);
|
||||
void printFloat(double, uint8_t);
|
||||
public:
|
||||
virtual void write(uint8_t) = 0;
|
||||
virtual void write(const char *str);
|
||||
virtual void write(const uint8_t *buffer, size_t size);
|
||||
|
||||
void print(const String &);
|
||||
void print(const char[]);
|
||||
void print(char, int = BYTE);
|
||||
void print(unsigned char, int = BYTE);
|
||||
void print(int, int = DEC);
|
||||
void print(unsigned int, int = DEC);
|
||||
void print(long, int = DEC);
|
||||
void print(unsigned long, int = DEC);
|
||||
void print(double, int = 2);
|
||||
|
||||
void println(const String &s);
|
||||
void println(const char[]);
|
||||
void println(char, int = BYTE);
|
||||
void println(unsigned char, int = BYTE);
|
||||
void println(int, int = DEC);
|
||||
void println(unsigned int, int = DEC);
|
||||
void println(long, int = DEC);
|
||||
void println(unsigned long, int = DEC);
|
||||
void println(double, int = 2);
|
||||
void println(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. 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
|
||||
*/
|
||||
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
class Stream : public Print
|
||||
{
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,601 @@
|
||||
/* Tone.cpp
|
||||
|
||||
A Tone Generator Library
|
||||
|
||||
Written by Brett Hagman
|
||||
|
||||
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
|
||||
|
||||
Version Modified By Date Comments
|
||||
------- ----------- -------- --------
|
||||
0001 B Hagman 09/08/02 Initial coding
|
||||
0002 B Hagman 09/08/18 Multiple pins
|
||||
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
|
||||
0004 B Hagman 09/09/26 Fixed problems with ATmega8
|
||||
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
|
||||
09/11/25 Changed pin toggle method to XOR
|
||||
09/11/25 Fixed timer0 from being excluded
|
||||
0006 D Mellis 09/12/29 Replaced objects with functions
|
||||
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
|
||||
*************************************************/
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "wiring.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
|
||||
#define TCCR2A TCCR2
|
||||
#define TCCR2B TCCR2
|
||||
#define COM2A1 COM21
|
||||
#define COM2A0 COM20
|
||||
#define OCR2A OCR2
|
||||
#define TIMSK2 TIMSK
|
||||
#define OCIE2A OCIE2
|
||||
#define TIMER2_COMPA_vect TIMER2_COMP_vect
|
||||
#define TIMSK1 TIMSK
|
||||
#endif
|
||||
|
||||
// timerx_toggle_count:
|
||||
// > 0 - duration specified
|
||||
// = 0 - stopped
|
||||
// < 0 - infinitely (until stop() method called, or new play() called)
|
||||
|
||||
#if !defined(__AVR_ATmega8__)
|
||||
volatile long timer0_toggle_count;
|
||||
volatile uint8_t *timer0_pin_port;
|
||||
volatile uint8_t timer0_pin_mask;
|
||||
#endif
|
||||
|
||||
volatile long timer1_toggle_count;
|
||||
volatile uint8_t *timer1_pin_port;
|
||||
volatile uint8_t timer1_pin_mask;
|
||||
volatile long timer2_toggle_count;
|
||||
volatile uint8_t *timer2_pin_port;
|
||||
volatile uint8_t timer2_pin_mask;
|
||||
|
||||
#if defined(TIMSK3)
|
||||
volatile long timer3_toggle_count;
|
||||
volatile uint8_t *timer3_pin_port;
|
||||
volatile uint8_t timer3_pin_mask;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK4)
|
||||
volatile long timer4_toggle_count;
|
||||
volatile uint8_t *timer4_pin_port;
|
||||
volatile uint8_t timer4_pin_mask;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK5)
|
||||
volatile long timer5_toggle_count;
|
||||
volatile uint8_t *timer5_pin_port;
|
||||
volatile uint8_t timer5_pin_mask;
|
||||
#endif
|
||||
|
||||
|
||||
// MLS: This does not make sense, the 3 options are the same
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
|
||||
|
||||
#elif defined(__AVR_ATmega8__)
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
|
||||
|
||||
#else
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
|
||||
// Leave timer 0 to last.
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static int8_t toneBegin(uint8_t _pin)
|
||||
{
|
||||
int8_t _timer = -1;
|
||||
|
||||
// if we're already using the pin, the timer should be configured.
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == _pin) {
|
||||
return pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
}
|
||||
}
|
||||
|
||||
// search for an unused timer.
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == 255) {
|
||||
tone_pins[i] = _pin;
|
||||
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_timer != -1)
|
||||
{
|
||||
// Set timer specific stuff
|
||||
// All timers in CTC mode
|
||||
// 8 bit timers will require changing prescalar values,
|
||||
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
|
||||
switch (_timer)
|
||||
{
|
||||
#if defined(TCCR0A) && defined(TCCR0B)
|
||||
case 0:
|
||||
// 8 bit timer
|
||||
TCCR0A = 0;
|
||||
TCCR0B = 0;
|
||||
bitWrite(TCCR0A, WGM01, 1);
|
||||
bitWrite(TCCR0B, CS00, 1);
|
||||
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer0_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
|
||||
case 1:
|
||||
// 16 bit timer
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
bitWrite(TCCR1B, WGM12, 1);
|
||||
bitWrite(TCCR1B, CS10, 1);
|
||||
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer1_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(TCCR2B)
|
||||
case 2:
|
||||
// 8 bit timer
|
||||
TCCR2A = 0;
|
||||
TCCR2B = 0;
|
||||
bitWrite(TCCR2A, WGM21, 1);
|
||||
bitWrite(TCCR2B, CS20, 1);
|
||||
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer2_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
|
||||
case 3:
|
||||
// 16 bit timer
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
bitWrite(TCCR3B, WGM32, 1);
|
||||
bitWrite(TCCR3B, CS30, 1);
|
||||
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer3_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
|
||||
case 4:
|
||||
// 16 bit timer
|
||||
TCCR4A = 0;
|
||||
TCCR4B = 0;
|
||||
#if defined(WGM42)
|
||||
bitWrite(TCCR4B, WGM42, 1);
|
||||
#elif defined(CS43)
|
||||
#warning this may not be correct
|
||||
// atmega32u4
|
||||
bitWrite(TCCR4B, CS43, 1);
|
||||
#endif
|
||||
bitWrite(TCCR4B, CS40, 1);
|
||||
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer4_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
|
||||
case 5:
|
||||
// 16 bit timer
|
||||
TCCR5A = 0;
|
||||
TCCR5B = 0;
|
||||
bitWrite(TCCR5B, WGM52, 1);
|
||||
bitWrite(TCCR5B, CS50, 1);
|
||||
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer5_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return _timer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// frequency (in hertz) and duration (in milliseconds).
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
uint8_t prescalarbits = 0b001;
|
||||
long toggle_count = 0;
|
||||
uint32_t ocr = 0;
|
||||
int8_t _timer;
|
||||
|
||||
_timer = toneBegin(_pin);
|
||||
|
||||
if (_timer >= 0)
|
||||
{
|
||||
// Set the pinMode as OUTPUT
|
||||
pinMode(_pin, OUTPUT);
|
||||
|
||||
// if we are using an 8 bit timer, scan through prescalars to find the best fit
|
||||
if (_timer == 0 || _timer == 2)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
prescalarbits = 0b001; // ck/1: same for both timers
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 8 - 1;
|
||||
prescalarbits = 0b010; // ck/8: same for both timers
|
||||
|
||||
if (_timer == 2 && ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 32 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b011 : 0b100;
|
||||
|
||||
if (_timer == 2 && ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 128 - 1;
|
||||
prescalarbits = 0b101;
|
||||
}
|
||||
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 256 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b100 : 0b110;
|
||||
if (ocr > 255)
|
||||
{
|
||||
// can't do any better than /1024
|
||||
ocr = F_CPU / frequency / 2 / 1024 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b101 : 0b111;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TCCR0B)
|
||||
if (_timer == 0)
|
||||
{
|
||||
TCCR0B = prescalarbits;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(TCCR2B)
|
||||
{
|
||||
TCCR2B = prescalarbits;
|
||||
}
|
||||
#else
|
||||
{
|
||||
// dummy place holder to make the above ifdefs work
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
|
||||
prescalarbits = 0b001;
|
||||
if (ocr > 0xffff)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
|
||||
if (_timer == 1)
|
||||
{
|
||||
#if defined(TCCR1B)
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
}
|
||||
#if defined(TCCR3B)
|
||||
else if (_timer == 3)
|
||||
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
#if defined(TCCR4B)
|
||||
else if (_timer == 4)
|
||||
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
#if defined(TCCR5B)
|
||||
else if (_timer == 5)
|
||||
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Calculate the toggle count
|
||||
if (duration > 0)
|
||||
{
|
||||
toggle_count = 2 * frequency * duration / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
toggle_count = -1;
|
||||
}
|
||||
|
||||
// Set the OCR for the given timer,
|
||||
// set the toggle count,
|
||||
// then turn on the interrupts
|
||||
switch (_timer)
|
||||
{
|
||||
|
||||
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
|
||||
case 0:
|
||||
OCR0A = ocr;
|
||||
timer0_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK0, OCIE0A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 1:
|
||||
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
|
||||
// this combination is for at least the ATmega32
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK, OCIE1A, 1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
|
||||
case 2:
|
||||
OCR2A = ocr;
|
||||
timer2_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK2, OCIE2A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK3)
|
||||
case 3:
|
||||
OCR3A = ocr;
|
||||
timer3_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK3, OCIE3A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK4)
|
||||
case 4:
|
||||
OCR4A = ocr;
|
||||
timer4_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK4, OCIE4A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
|
||||
case 5:
|
||||
OCR5A = ocr;
|
||||
timer5_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK5, OCIE5A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// XXX: this function only works properly for timer 2 (the only one we use
|
||||
// currently). for the others, it should end the tone, but won't restore
|
||||
// proper PWM functionality for the timer.
|
||||
void disableTimer(uint8_t _timer)
|
||||
{
|
||||
switch (_timer)
|
||||
{
|
||||
case 0:
|
||||
#if defined(TIMSK0)
|
||||
TIMSK0 = 0;
|
||||
#elif defined(TIMSK)
|
||||
TIMSK = 0; // atmega32
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(TIMSK1) && defined(OCIE1A)
|
||||
case 1:
|
||||
bitWrite(TIMSK1, OCIE1A, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 2:
|
||||
#if defined(TIMSK2) && defined(OCIE2A)
|
||||
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(WGM20)
|
||||
TCCR2A = (1 << WGM20);
|
||||
#endif
|
||||
#if defined(TCCR2B) && defined(CS22)
|
||||
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
|
||||
#endif
|
||||
#if defined(OCR2A)
|
||||
OCR2A = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(TIMSK3)
|
||||
case 3:
|
||||
TIMSK3 = 0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK4)
|
||||
case 4:
|
||||
TIMSK4 = 0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK5)
|
||||
case 5:
|
||||
TIMSK5 = 0;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void noTone(uint8_t _pin)
|
||||
{
|
||||
int8_t _timer = -1;
|
||||
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == _pin) {
|
||||
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
tone_pins[i] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
disableTimer(_timer);
|
||||
|
||||
digitalWrite(_pin, 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if !defined(__AVR_ATmega8__)
|
||||
ISR(TIMER0_COMPA_vect)
|
||||
{
|
||||
if (timer0_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer0_pin_port ^= timer0_pin_mask;
|
||||
|
||||
if (timer0_toggle_count > 0)
|
||||
timer0_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(0);
|
||||
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (timer1_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer1_pin_port ^= timer1_pin_mask;
|
||||
|
||||
if (timer1_toggle_count > 0)
|
||||
timer1_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(1);
|
||||
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ISR(TIMER2_COMPA_vect)
|
||||
{
|
||||
|
||||
if (timer2_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer2_pin_port ^= timer2_pin_mask;
|
||||
|
||||
if (timer2_toggle_count > 0)
|
||||
timer2_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to call noTone() so that the tone_pins[] entry is reset, so the
|
||||
// timer gets initialized next time we call tone().
|
||||
// XXX: this assumes timer 2 is always the first one used.
|
||||
noTone(tone_pins[0]);
|
||||
// disableTimer(2);
|
||||
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#if 0
|
||||
|
||||
ISR(TIMER3_COMPA_vect)
|
||||
{
|
||||
if (timer3_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer3_pin_port ^= timer3_pin_mask;
|
||||
|
||||
if (timer3_toggle_count > 0)
|
||||
timer3_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(3);
|
||||
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
|
||||
ISR(TIMER4_COMPA_vect)
|
||||
{
|
||||
if (timer4_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer4_pin_port ^= timer4_pin_mask;
|
||||
|
||||
if (timer4_toggle_count > 0)
|
||||
timer4_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(4);
|
||||
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
|
||||
ISR(TIMER5_COMPA_vect)
|
||||
{
|
||||
if (timer5_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer5_pin_port ^= timer5_pin_mask;
|
||||
|
||||
if (timer5_toggle_count > 0)
|
||||
timer5_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(5);
|
||||
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
WCharacter.h - Character utility functions for Wiring & Arduino
|
||||
Copyright (c) 2010 Hernando Barragan. 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
|
||||
*/
|
||||
|
||||
#ifndef Character_h
|
||||
#define Character_h
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
// WCharacter.h prototypes
|
||||
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
|
||||
inline boolean isAlpha(int c) __attribute__((always_inline));
|
||||
inline boolean isAscii(int c) __attribute__((always_inline));
|
||||
inline boolean isWhitespace(int c) __attribute__((always_inline));
|
||||
inline boolean isControl(int c) __attribute__((always_inline));
|
||||
inline boolean isDigit(int c) __attribute__((always_inline));
|
||||
inline boolean isGraph(int c) __attribute__((always_inline));
|
||||
inline boolean isLowerCase(int c) __attribute__((always_inline));
|
||||
inline boolean isPrintable(int c) __attribute__((always_inline));
|
||||
inline boolean isPunct(int c) __attribute__((always_inline));
|
||||
inline boolean isSpace(int c) __attribute__((always_inline));
|
||||
inline boolean isUpperCase(int c) __attribute__((always_inline));
|
||||
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
|
||||
inline int toAscii(int c) __attribute__((always_inline));
|
||||
inline int toLowerCase(int c) __attribute__((always_inline));
|
||||
inline int toUpperCase(int c)__attribute__((always_inline));
|
||||
|
||||
|
||||
// Checks for an alphanumeric character.
|
||||
// It is equivalent to (isalpha(c) || isdigit(c)).
|
||||
inline boolean isAlphaNumeric(int c)
|
||||
{
|
||||
return ( isalnum(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for an alphabetic character.
|
||||
// It is equivalent to (isupper(c) || islower(c)).
|
||||
inline boolean isAlpha(int c)
|
||||
{
|
||||
return ( isalpha(c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks whether c is a 7-bit unsigned char value
|
||||
// that fits into the ASCII character set.
|
||||
inline boolean isAscii(int c)
|
||||
{
|
||||
return ( isascii (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a blank character, that is, a space or a tab.
|
||||
inline boolean isWhitespace(int c)
|
||||
{
|
||||
return ( isblank (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a control character.
|
||||
inline boolean isControl(int c)
|
||||
{
|
||||
return ( iscntrl (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a digit (0 through 9).
|
||||
inline boolean isDigit(int c)
|
||||
{
|
||||
return ( isdigit (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character except space.
|
||||
inline boolean isGraph(int c)
|
||||
{
|
||||
return ( isgraph (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a lower-case character.
|
||||
inline boolean isLowerCase(int c)
|
||||
{
|
||||
return (islower (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character including space.
|
||||
inline boolean isPrintable(int c)
|
||||
{
|
||||
return ( isprint (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for any printable character which is not a space
|
||||
// or an alphanumeric character.
|
||||
inline boolean isPunct(int c)
|
||||
{
|
||||
return ( ispunct (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for white-space characters. For the avr-libc library,
|
||||
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
||||
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
|
||||
inline boolean isSpace(int c)
|
||||
{
|
||||
return ( isspace (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for an uppercase letter.
|
||||
inline boolean isUpperCase(int c)
|
||||
{
|
||||
return ( isupper (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
|
||||
// 8 9 a b c d e f A B C D E F.
|
||||
inline boolean isHexadecimalDigit(int c)
|
||||
{
|
||||
return ( isxdigit (c) == 0 ? false : true);
|
||||
}
|
||||
|
||||
|
||||
// Converts c to a 7-bit unsigned char value that fits into the
|
||||
// ASCII character set, by clearing the high-order bits.
|
||||
inline int toAscii(int c)
|
||||
{
|
||||
return toascii (c);
|
||||
}
|
||||
|
||||
|
||||
// Warning:
|
||||
// Many people will be unhappy if you use this function.
|
||||
// This function will convert accented letters into random
|
||||
// characters.
|
||||
|
||||
// Converts the letter c to lower case, if possible.
|
||||
inline int toLowerCase(int c)
|
||||
{
|
||||
return tolower (c);
|
||||
}
|
||||
|
||||
|
||||
// Converts the letter c to upper case, if possible.
|
||||
inline int toUpperCase(int c)
|
||||
{
|
||||
return toupper (c);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
#include "wiring.h"
|
||||
@@ -0,0 +1,249 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Wiring project - http://wiring.uniandes.edu.co
|
||||
|
||||
Copyright (c) 2004-05 Hernando Barragan
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 24 November 2006 by David A. Mellis
|
||||
Modified 1 August 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "WConstants.h"
|
||||
#include "wiring_private.h"
|
||||
|
||||
volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
|
||||
// volatile static voidFuncPtr twiIntFunc;
|
||||
|
||||
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
|
||||
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
|
||||
intFunc[interruptNum] = userFunc;
|
||||
|
||||
// Configure the interrupt mode (trigger on low input, any change, rising
|
||||
// edge, or falling edge). The mode constants were chosen to correspond
|
||||
// to the configuration bits in the hardware register, so we simply shift
|
||||
// the mode into place.
|
||||
|
||||
// Enable the interrupt.
|
||||
|
||||
switch (interruptNum) {
|
||||
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
case 2:
|
||||
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
EIMSK |= (1 << INT0);
|
||||
break;
|
||||
case 3:
|
||||
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
EIMSK |= (1 << INT1);
|
||||
break;
|
||||
case 4:
|
||||
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
|
||||
EIMSK |= (1 << INT2);
|
||||
break;
|
||||
case 5:
|
||||
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
|
||||
EIMSK |= (1 << INT3);
|
||||
break;
|
||||
case 0:
|
||||
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
|
||||
EIMSK |= (1 << INT4);
|
||||
break;
|
||||
case 1:
|
||||
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
|
||||
EIMSK |= (1 << INT5);
|
||||
break;
|
||||
case 6:
|
||||
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
|
||||
EIMSK |= (1 << INT6);
|
||||
break;
|
||||
case 7:
|
||||
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
|
||||
EIMSK |= (1 << INT7);
|
||||
break;
|
||||
#else
|
||||
case 0:
|
||||
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
|
||||
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
EIMSK |= (1 << INT0);
|
||||
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
|
||||
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
GICR |= (1 << INT0);
|
||||
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
|
||||
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
GIMSK |= (1 << INT0);
|
||||
#else
|
||||
#error attachInterrupt not finished for this CPU (case 0)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 1:
|
||||
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
|
||||
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
EIMSK |= (1 << INT1);
|
||||
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
|
||||
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
GICR |= (1 << INT1);
|
||||
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
|
||||
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
GIMSK |= (1 << INT1);
|
||||
#else
|
||||
#warning attachInterrupt may need some more work for this cpu (case 1)
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detachInterrupt(uint8_t interruptNum) {
|
||||
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
|
||||
// Disable the interrupt. (We can't assume that interruptNum is equal
|
||||
// to the number of the EIMSK bit to clear, as this isn't true on the
|
||||
// ATmega8. There, INT0 is 6 and INT1 is 7.)
|
||||
switch (interruptNum) {
|
||||
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
case 2:
|
||||
EIMSK &= ~(1 << INT0);
|
||||
break;
|
||||
case 3:
|
||||
EIMSK &= ~(1 << INT1);
|
||||
break;
|
||||
case 4:
|
||||
EIMSK &= ~(1 << INT2);
|
||||
break;
|
||||
case 5:
|
||||
EIMSK &= ~(1 << INT3);
|
||||
break;
|
||||
case 0:
|
||||
EIMSK &= ~(1 << INT4);
|
||||
break;
|
||||
case 1:
|
||||
EIMSK &= ~(1 << INT5);
|
||||
break;
|
||||
case 6:
|
||||
EIMSK &= ~(1 << INT6);
|
||||
break;
|
||||
case 7:
|
||||
EIMSK &= ~(1 << INT7);
|
||||
break;
|
||||
#else
|
||||
case 0:
|
||||
#if defined(EIMSK) && defined(INT0)
|
||||
EIMSK &= ~(1 << INT0);
|
||||
#elif defined(GICR) && defined(ISC00)
|
||||
GICR &= ~(1 << INT0); // atmega32
|
||||
#elif defined(GIMSK) && defined(INT0)
|
||||
GIMSK &= ~(1 << INT0);
|
||||
#else
|
||||
#error detachInterrupt not finished for this cpu
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 1:
|
||||
#if defined(EIMSK) && defined(INT1)
|
||||
EIMSK &= ~(1 << INT1);
|
||||
#elif defined(GICR) && defined(INT1)
|
||||
GICR &= ~(1 << INT1); // atmega32
|
||||
#elif defined(GIMSK) && defined(INT1)
|
||||
GIMSK &= ~(1 << INT1);
|
||||
#else
|
||||
#warning detachInterrupt may need some more work for this cpu (case 1)
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
intFunc[interruptNum] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void attachInterruptTwi(void (*userFunc)(void) ) {
|
||||
twiIntFunc = userFunc;
|
||||
}
|
||||
*/
|
||||
|
||||
#if defined(EICRA) && defined(EICRB)
|
||||
|
||||
SIGNAL(INT0_vect) {
|
||||
if(intFunc[EXTERNAL_INT_2])
|
||||
intFunc[EXTERNAL_INT_2]();
|
||||
}
|
||||
|
||||
SIGNAL(INT1_vect) {
|
||||
if(intFunc[EXTERNAL_INT_3])
|
||||
intFunc[EXTERNAL_INT_3]();
|
||||
}
|
||||
|
||||
SIGNAL(INT2_vect) {
|
||||
if(intFunc[EXTERNAL_INT_4])
|
||||
intFunc[EXTERNAL_INT_4]();
|
||||
}
|
||||
|
||||
SIGNAL(INT3_vect) {
|
||||
if(intFunc[EXTERNAL_INT_5])
|
||||
intFunc[EXTERNAL_INT_5]();
|
||||
}
|
||||
|
||||
SIGNAL(INT4_vect) {
|
||||
if(intFunc[EXTERNAL_INT_0])
|
||||
intFunc[EXTERNAL_INT_0]();
|
||||
}
|
||||
|
||||
SIGNAL(INT5_vect) {
|
||||
if(intFunc[EXTERNAL_INT_1])
|
||||
intFunc[EXTERNAL_INT_1]();
|
||||
}
|
||||
|
||||
SIGNAL(INT6_vect) {
|
||||
if(intFunc[EXTERNAL_INT_6])
|
||||
intFunc[EXTERNAL_INT_6]();
|
||||
}
|
||||
|
||||
SIGNAL(INT7_vect) {
|
||||
if(intFunc[EXTERNAL_INT_7])
|
||||
intFunc[EXTERNAL_INT_7]();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SIGNAL(INT0_vect) {
|
||||
if(intFunc[EXTERNAL_INT_0])
|
||||
intFunc[EXTERNAL_INT_0]();
|
||||
}
|
||||
|
||||
SIGNAL(INT1_vect) {
|
||||
if(intFunc[EXTERNAL_INT_1])
|
||||
intFunc[EXTERNAL_INT_1]();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
SIGNAL(SIG_2WIRE_SERIAL) {
|
||||
if(twiIntFunc)
|
||||
twiIntFunc();
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Wiring project - http://wiring.org.co
|
||||
Copyright (c) 2004-06 Hernando Barragan
|
||||
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "stdlib.h"
|
||||
}
|
||||
|
||||
void randomSeed(unsigned int seed)
|
||||
{
|
||||
if (seed != 0) {
|
||||
srandom(seed);
|
||||
}
|
||||
}
|
||||
|
||||
long random(long howbig)
|
||||
{
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return random() % howbig;
|
||||
}
|
||||
|
||||
long random(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w) { return w; }
|
||||
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef WProgram_h
|
||||
#define WProgram_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "wiring.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h, byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long, long);
|
||||
void randomSeed(unsigned int);
|
||||
long map(long, long, long, long, long);
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
const static uint8_t A0 = 54;
|
||||
const static uint8_t A1 = 55;
|
||||
const static uint8_t A2 = 56;
|
||||
const static uint8_t A3 = 57;
|
||||
const static uint8_t A4 = 58;
|
||||
const static uint8_t A5 = 59;
|
||||
const static uint8_t A6 = 60;
|
||||
const static uint8_t A7 = 61;
|
||||
const static uint8_t A8 = 62;
|
||||
const static uint8_t A9 = 63;
|
||||
const static uint8_t A10 = 64;
|
||||
const static uint8_t A11 = 65;
|
||||
const static uint8_t A12 = 66;
|
||||
const static uint8_t A13 = 67;
|
||||
const static uint8_t A14 = 68;
|
||||
const static uint8_t A15 = 69;
|
||||
#else
|
||||
const static uint8_t A0 = 14;
|
||||
const static uint8_t A1 = 15;
|
||||
const static uint8_t A2 = 16;
|
||||
const static uint8_t A3 = 17;
|
||||
const static uint8_t A4 = 18;
|
||||
const static uint8_t A5 = 19;
|
||||
const static uint8_t A6 = 20;
|
||||
const static uint8_t A7 = 21;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
WString.cpp - String library for Wiring & Arduino
|
||||
Copyright (c) 2009-10 Hernando Barragan. All rights 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
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "WProgram.h"
|
||||
#include "WString.h"
|
||||
|
||||
|
||||
String::String( const char *value )
|
||||
{
|
||||
if ( value == NULL )
|
||||
value = "";
|
||||
getBuffer( _length = strlen( value ) );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, value );
|
||||
}
|
||||
|
||||
String::String( const String &value )
|
||||
{
|
||||
getBuffer( _length = value._length );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, value._buffer );
|
||||
}
|
||||
|
||||
String::String( const char value )
|
||||
{
|
||||
_length = 1;
|
||||
getBuffer(1);
|
||||
if ( _buffer != NULL ) {
|
||||
_buffer[0] = value;
|
||||
_buffer[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
String::String( const unsigned char value )
|
||||
{
|
||||
_length = 1;
|
||||
getBuffer(1);
|
||||
if ( _buffer != NULL) {
|
||||
_buffer[0] = value;
|
||||
_buffer[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
String::String( const int value, const int base )
|
||||
{
|
||||
char buf[33];
|
||||
itoa((signed long)value, buf, base);
|
||||
getBuffer( _length = strlen(buf) );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, buf );
|
||||
}
|
||||
|
||||
String::String( const unsigned int value, const int base )
|
||||
{
|
||||
char buf[33];
|
||||
ultoa((unsigned long)value, buf, base);
|
||||
getBuffer( _length = strlen(buf) );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, buf );
|
||||
}
|
||||
|
||||
String::String( const long value, const int base )
|
||||
{
|
||||
char buf[33];
|
||||
ltoa(value, buf, base);
|
||||
getBuffer( _length = strlen(buf) );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, buf );
|
||||
}
|
||||
|
||||
String::String( const unsigned long value, const int base )
|
||||
{
|
||||
char buf[33];
|
||||
ultoa(value, buf, 10);
|
||||
getBuffer( _length = strlen(buf) );
|
||||
if ( _buffer != NULL )
|
||||
strcpy( _buffer, buf );
|
||||
}
|
||||
|
||||
char String::charAt( unsigned int loc ) const
|
||||
{
|
||||
return operator[]( loc );
|
||||
}
|
||||
|
||||
void String::setCharAt( unsigned int loc, const char aChar )
|
||||
{
|
||||
if(_buffer == NULL) return;
|
||||
if(_length > loc) {
|
||||
_buffer[loc] = aChar;
|
||||
}
|
||||
}
|
||||
|
||||
int String::compareTo( const String &s2 ) const
|
||||
{
|
||||
return strcmp( _buffer, s2._buffer );
|
||||
}
|
||||
|
||||
const String & String::concat( const String &s2 )
|
||||
{
|
||||
return (*this) += s2;
|
||||
}
|
||||
|
||||
const String & String::operator=( const String &rhs )
|
||||
{
|
||||
if ( this == &rhs )
|
||||
return *this;
|
||||
|
||||
if ( rhs._length > _length )
|
||||
{
|
||||
free(_buffer);
|
||||
getBuffer( rhs._length );
|
||||
}
|
||||
|
||||
if ( _buffer != NULL ) {
|
||||
_length = rhs._length;
|
||||
strcpy( _buffer, rhs._buffer );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//const String & String::operator+=( const char aChar )
|
||||
//{
|
||||
// if ( _length == _capacity )
|
||||
// doubleBuffer();
|
||||
//
|
||||
// _buffer[ _length++ ] = aChar;
|
||||
// _buffer[ _length ] = '\0';
|
||||
// return *this;
|
||||
//}
|
||||
|
||||
const String & String::operator+=( const String &other )
|
||||
{
|
||||
_length += other._length;
|
||||
if ( _length > _capacity )
|
||||
{
|
||||
char *temp = (char *)realloc(_buffer, _length + 1);
|
||||
if ( temp != NULL ) {
|
||||
_buffer = temp;
|
||||
_capacity = _length;
|
||||
} else {
|
||||
_length -= other._length;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
strcat( _buffer, other._buffer );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
int String::operator==( const String &rhs ) const
|
||||
{
|
||||
return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 );
|
||||
}
|
||||
|
||||
int String::operator!=( const String &rhs ) const
|
||||
{
|
||||
return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 );
|
||||
}
|
||||
|
||||
int String::operator<( const String &rhs ) const
|
||||
{
|
||||
return strcmp( _buffer, rhs._buffer ) < 0;
|
||||
}
|
||||
|
||||
int String::operator>( const String &rhs ) const
|
||||
{
|
||||
return strcmp( _buffer, rhs._buffer ) > 0;
|
||||
}
|
||||
|
||||
int String::operator<=( const String &rhs ) const
|
||||
{
|
||||
return strcmp( _buffer, rhs._buffer ) <= 0;
|
||||
}
|
||||
|
||||
int String::operator>=( const String & rhs ) const
|
||||
{
|
||||
return strcmp( _buffer, rhs._buffer ) >= 0;
|
||||
}
|
||||
|
||||
char & String::operator[]( unsigned int index )
|
||||
{
|
||||
static char dummy_writable_char;
|
||||
if (index >= _length || !_buffer) {
|
||||
dummy_writable_char = 0;
|
||||
return dummy_writable_char;
|
||||
}
|
||||
return _buffer[ index ];
|
||||
}
|
||||
|
||||
char String::operator[]( unsigned int index ) const
|
||||
{
|
||||
// need to check for valid index, to do later
|
||||
return _buffer[ index ];
|
||||
}
|
||||
|
||||
boolean String::endsWith( const String &s2 ) const
|
||||
{
|
||||
if ( _length < s2._length )
|
||||
return 0;
|
||||
|
||||
return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0;
|
||||
}
|
||||
|
||||
boolean String::equals( const String &s2 ) const
|
||||
{
|
||||
return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 );
|
||||
}
|
||||
|
||||
boolean String::equalsIgnoreCase( const String &s2 ) const
|
||||
{
|
||||
if ( this == &s2 )
|
||||
return true; //1;
|
||||
else if ( _length != s2._length )
|
||||
return false; //0;
|
||||
|
||||
return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0;
|
||||
}
|
||||
|
||||
String String::replace( char findChar, char replaceChar )
|
||||
{
|
||||
if ( _buffer == NULL ) return *this;
|
||||
String theReturn = _buffer;
|
||||
char* temp = theReturn._buffer;
|
||||
while( (temp = strchr( temp, findChar )) != 0 )
|
||||
*temp = replaceChar;
|
||||
|
||||
return theReturn;
|
||||
}
|
||||
|
||||
String String::replace( const String& match, const String& replace )
|
||||
{
|
||||
if ( _buffer == NULL ) return *this;
|
||||
String temp = _buffer, newString;
|
||||
|
||||
int loc;
|
||||
while ( (loc = temp.indexOf( match )) != -1 )
|
||||
{
|
||||
newString += temp.substring( 0, loc );
|
||||
newString += replace;
|
||||
temp = temp.substring( loc + match._length );
|
||||
}
|
||||
newString += temp;
|
||||
return newString;
|
||||
}
|
||||
|
||||
int String::indexOf( char temp ) const
|
||||
{
|
||||
return indexOf( temp, 0 );
|
||||
}
|
||||
|
||||
int String::indexOf( char ch, unsigned int fromIndex ) const
|
||||
{
|
||||
if ( fromIndex >= _length )
|
||||
return -1;
|
||||
|
||||
const char* temp = strchr( &_buffer[fromIndex], ch );
|
||||
if ( temp == NULL )
|
||||
return -1;
|
||||
|
||||
return temp - _buffer;
|
||||
}
|
||||
|
||||
int String::indexOf( const String &s2 ) const
|
||||
{
|
||||
return indexOf( s2, 0 );
|
||||
}
|
||||
|
||||
int String::indexOf( const String &s2, unsigned int fromIndex ) const
|
||||
{
|
||||
if ( fromIndex >= _length )
|
||||
return -1;
|
||||
|
||||
const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer );
|
||||
|
||||
if ( theFind == NULL )
|
||||
return -1;
|
||||
|
||||
return theFind - _buffer; // pointer subtraction
|
||||
}
|
||||
|
||||
int String::lastIndexOf( char theChar ) const
|
||||
{
|
||||
return lastIndexOf( theChar, _length - 1 );
|
||||
}
|
||||
|
||||
int String::lastIndexOf( char ch, unsigned int fromIndex ) const
|
||||
{
|
||||
if ( fromIndex >= _length )
|
||||
return -1;
|
||||
|
||||
char tempchar = _buffer[fromIndex + 1];
|
||||
_buffer[fromIndex + 1] = '\0';
|
||||
char* temp = strrchr( _buffer, ch );
|
||||
_buffer[fromIndex + 1] = tempchar;
|
||||
|
||||
if ( temp == NULL )
|
||||
return -1;
|
||||
|
||||
return temp - _buffer;
|
||||
}
|
||||
|
||||
int String::lastIndexOf( const String &s2 ) const
|
||||
{
|
||||
return lastIndexOf( s2, _length - s2._length );
|
||||
}
|
||||
|
||||
int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const
|
||||
{
|
||||
// check for empty strings
|
||||
if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length )
|
||||
return -1;
|
||||
|
||||
// matching first character
|
||||
char temp = s2[ 0 ];
|
||||
|
||||
for ( int i = fromIndex; i >= 0; i-- )
|
||||
{
|
||||
if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
boolean String::startsWith( const String &s2 ) const
|
||||
{
|
||||
if ( _length < s2._length )
|
||||
return 0;
|
||||
|
||||
return startsWith( s2, 0 );
|
||||
}
|
||||
|
||||
boolean String::startsWith( const String &s2, unsigned int offset ) const
|
||||
{
|
||||
if ( offset > _length - s2._length )
|
||||
return 0;
|
||||
|
||||
return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0;
|
||||
}
|
||||
|
||||
String String::substring( unsigned int left ) const
|
||||
{
|
||||
return substring( left, _length );
|
||||
}
|
||||
|
||||
String String::substring( unsigned int left, unsigned int right ) const
|
||||
{
|
||||
if ( left > right )
|
||||
{
|
||||
int temp = right;
|
||||
right = left;
|
||||
left = temp;
|
||||
}
|
||||
|
||||
if ( right > _length )
|
||||
{
|
||||
right = _length;
|
||||
}
|
||||
|
||||
char temp = _buffer[ right ]; // save the replaced character
|
||||
_buffer[ right ] = '\0';
|
||||
String outPut = ( _buffer + left ); // pointer arithmetic
|
||||
_buffer[ right ] = temp; //restore character
|
||||
return outPut;
|
||||
}
|
||||
|
||||
String String::toLowerCase() const
|
||||
{
|
||||
String temp = _buffer;
|
||||
|
||||
for ( unsigned int i = 0; i < _length; i++ )
|
||||
temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] );
|
||||
return temp;
|
||||
}
|
||||
|
||||
String String::toUpperCase() const
|
||||
{
|
||||
String temp = _buffer;
|
||||
|
||||
for ( unsigned int i = 0; i < _length; i++ )
|
||||
temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] );
|
||||
return temp;
|
||||
}
|
||||
|
||||
String String::trim() const
|
||||
{
|
||||
if ( _buffer == NULL ) return *this;
|
||||
String temp = _buffer;
|
||||
unsigned int i,j;
|
||||
|
||||
for ( i = 0; i < _length; i++ )
|
||||
{
|
||||
if ( !isspace(_buffer[i]) )
|
||||
break;
|
||||
}
|
||||
|
||||
for ( j = temp._length - 1; j > i; j-- )
|
||||
{
|
||||
if ( !isspace(_buffer[j]) )
|
||||
break;
|
||||
}
|
||||
|
||||
return temp.substring( i, j + 1);
|
||||
}
|
||||
|
||||
void String::getBytes(unsigned char *buf, unsigned int bufsize)
|
||||
{
|
||||
if (!bufsize || !buf) return;
|
||||
unsigned int len = bufsize - 1;
|
||||
if (len > _length) len = _length;
|
||||
strncpy((char *)buf, _buffer, len);
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
void String::toCharArray(char *buf, unsigned int bufsize)
|
||||
{
|
||||
if (!bufsize || !buf) return;
|
||||
unsigned int len = bufsize - 1;
|
||||
if (len > _length) len = _length;
|
||||
strncpy(buf, _buffer, len);
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
|
||||
long String::toInt() {
|
||||
return atol(_buffer);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
WString.h - String library for Wiring & Arduino
|
||||
Copyright (c) 2009-10 Hernando Barragan. 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
|
||||
*/
|
||||
|
||||
#ifndef String_h
|
||||
#define String_h
|
||||
|
||||
//#include "WProgram.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
String( const char *value = "" );
|
||||
String( const String &value );
|
||||
String( const char );
|
||||
String( const unsigned char );
|
||||
String( const int, const int base=10);
|
||||
String( const unsigned int, const int base=10 );
|
||||
String( const long, const int base=10 );
|
||||
String( const unsigned long, const int base=10 );
|
||||
~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0;
|
||||
|
||||
// operators
|
||||
const String & operator = ( const String &rhs );
|
||||
const String & operator +=( const String &rhs );
|
||||
//const String & operator +=( const char );
|
||||
int operator ==( const String &rhs ) const;
|
||||
int operator !=( const String &rhs ) const;
|
||||
int operator < ( const String &rhs ) const;
|
||||
int operator > ( const String &rhs ) const;
|
||||
int operator <=( const String &rhs ) const;
|
||||
int operator >=( const String &rhs ) const;
|
||||
char operator []( unsigned int index ) const;
|
||||
char& operator []( unsigned int index );
|
||||
//operator const char *() const { return _buffer; }
|
||||
|
||||
// general methods
|
||||
char charAt( unsigned int index ) const;
|
||||
int compareTo( const String &anotherString ) const;
|
||||
unsigned char endsWith( const String &suffix ) const;
|
||||
unsigned char equals( const String &anObject ) const;
|
||||
unsigned char equalsIgnoreCase( const String &anotherString ) const;
|
||||
int indexOf( char ch ) const;
|
||||
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||
int indexOf( const String &str ) const;
|
||||
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( char ch ) const;
|
||||
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||
int lastIndexOf( const String &str ) const;
|
||||
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||
const unsigned int length( ) const { return _length; }
|
||||
void setCharAt(unsigned int index, const char ch);
|
||||
unsigned char startsWith( const String &prefix ) const;
|
||||
unsigned char startsWith( const String &prefix, unsigned int toffset ) const;
|
||||
String substring( unsigned int beginIndex ) const;
|
||||
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||
String toLowerCase( ) const;
|
||||
String toUpperCase( ) const;
|
||||
String trim( ) const;
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize);
|
||||
void toCharArray(char *buf, unsigned int bufsize);
|
||||
long toInt( );
|
||||
const String& concat( const String &str );
|
||||
String replace( char oldChar, char newChar );
|
||||
String replace( const String& match, const String& replace );
|
||||
friend String operator + ( String lhs, const String &rhs );
|
||||
|
||||
protected:
|
||||
char *_buffer; // the actual char array
|
||||
unsigned int _capacity; // the array length minus one (for the '\0')
|
||||
unsigned int _length; // the String length (not counting the '\0')
|
||||
|
||||
void getBuffer(unsigned int maxStrLen);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
// allocate buffer space
|
||||
inline void String::getBuffer(unsigned int maxStrLen)
|
||||
{
|
||||
_capacity = maxStrLen;
|
||||
_buffer = (char *) malloc(_capacity + 1);
|
||||
if (_buffer == NULL) _length = _capacity = 0;
|
||||
}
|
||||
|
||||
inline String operator+( String lhs, const String &rhs )
|
||||
{
|
||||
return lhs += rhs;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,515 @@
|
||||
#ifndef Binary_h
|
||||
#define Binary_h
|
||||
|
||||
#define B0 0
|
||||
#define B00 0
|
||||
#define B000 0
|
||||
#define B0000 0
|
||||
#define B00000 0
|
||||
#define B000000 0
|
||||
#define B0000000 0
|
||||
#define B00000000 0
|
||||
#define B1 1
|
||||
#define B01 1
|
||||
#define B001 1
|
||||
#define B0001 1
|
||||
#define B00001 1
|
||||
#define B000001 1
|
||||
#define B0000001 1
|
||||
#define B00000001 1
|
||||
#define B10 2
|
||||
#define B010 2
|
||||
#define B0010 2
|
||||
#define B00010 2
|
||||
#define B000010 2
|
||||
#define B0000010 2
|
||||
#define B00000010 2
|
||||
#define B11 3
|
||||
#define B011 3
|
||||
#define B0011 3
|
||||
#define B00011 3
|
||||
#define B000011 3
|
||||
#define B0000011 3
|
||||
#define B00000011 3
|
||||
#define B100 4
|
||||
#define B0100 4
|
||||
#define B00100 4
|
||||
#define B000100 4
|
||||
#define B0000100 4
|
||||
#define B00000100 4
|
||||
#define B101 5
|
||||
#define B0101 5
|
||||
#define B00101 5
|
||||
#define B000101 5
|
||||
#define B0000101 5
|
||||
#define B00000101 5
|
||||
#define B110 6
|
||||
#define B0110 6
|
||||
#define B00110 6
|
||||
#define B000110 6
|
||||
#define B0000110 6
|
||||
#define B00000110 6
|
||||
#define B111 7
|
||||
#define B0111 7
|
||||
#define B00111 7
|
||||
#define B000111 7
|
||||
#define B0000111 7
|
||||
#define B00000111 7
|
||||
#define B1000 8
|
||||
#define B01000 8
|
||||
#define B001000 8
|
||||
#define B0001000 8
|
||||
#define B00001000 8
|
||||
#define B1001 9
|
||||
#define B01001 9
|
||||
#define B001001 9
|
||||
#define B0001001 9
|
||||
#define B00001001 9
|
||||
#define B1010 10
|
||||
#define B01010 10
|
||||
#define B001010 10
|
||||
#define B0001010 10
|
||||
#define B00001010 10
|
||||
#define B1011 11
|
||||
#define B01011 11
|
||||
#define B001011 11
|
||||
#define B0001011 11
|
||||
#define B00001011 11
|
||||
#define B1100 12
|
||||
#define B01100 12
|
||||
#define B001100 12
|
||||
#define B0001100 12
|
||||
#define B00001100 12
|
||||
#define B1101 13
|
||||
#define B01101 13
|
||||
#define B001101 13
|
||||
#define B0001101 13
|
||||
#define B00001101 13
|
||||
#define B1110 14
|
||||
#define B01110 14
|
||||
#define B001110 14
|
||||
#define B0001110 14
|
||||
#define B00001110 14
|
||||
#define B1111 15
|
||||
#define B01111 15
|
||||
#define B001111 15
|
||||
#define B0001111 15
|
||||
#define B00001111 15
|
||||
#define B10000 16
|
||||
#define B010000 16
|
||||
#define B0010000 16
|
||||
#define B00010000 16
|
||||
#define B10001 17
|
||||
#define B010001 17
|
||||
#define B0010001 17
|
||||
#define B00010001 17
|
||||
#define B10010 18
|
||||
#define B010010 18
|
||||
#define B0010010 18
|
||||
#define B00010010 18
|
||||
#define B10011 19
|
||||
#define B010011 19
|
||||
#define B0010011 19
|
||||
#define B00010011 19
|
||||
#define B10100 20
|
||||
#define B010100 20
|
||||
#define B0010100 20
|
||||
#define B00010100 20
|
||||
#define B10101 21
|
||||
#define B010101 21
|
||||
#define B0010101 21
|
||||
#define B00010101 21
|
||||
#define B10110 22
|
||||
#define B010110 22
|
||||
#define B0010110 22
|
||||
#define B00010110 22
|
||||
#define B10111 23
|
||||
#define B010111 23
|
||||
#define B0010111 23
|
||||
#define B00010111 23
|
||||
#define B11000 24
|
||||
#define B011000 24
|
||||
#define B0011000 24
|
||||
#define B00011000 24
|
||||
#define B11001 25
|
||||
#define B011001 25
|
||||
#define B0011001 25
|
||||
#define B00011001 25
|
||||
#define B11010 26
|
||||
#define B011010 26
|
||||
#define B0011010 26
|
||||
#define B00011010 26
|
||||
#define B11011 27
|
||||
#define B011011 27
|
||||
#define B0011011 27
|
||||
#define B00011011 27
|
||||
#define B11100 28
|
||||
#define B011100 28
|
||||
#define B0011100 28
|
||||
#define B00011100 28
|
||||
#define B11101 29
|
||||
#define B011101 29
|
||||
#define B0011101 29
|
||||
#define B00011101 29
|
||||
#define B11110 30
|
||||
#define B011110 30
|
||||
#define B0011110 30
|
||||
#define B00011110 30
|
||||
#define B11111 31
|
||||
#define B011111 31
|
||||
#define B0011111 31
|
||||
#define B00011111 31
|
||||
#define B100000 32
|
||||
#define B0100000 32
|
||||
#define B00100000 32
|
||||
#define B100001 33
|
||||
#define B0100001 33
|
||||
#define B00100001 33
|
||||
#define B100010 34
|
||||
#define B0100010 34
|
||||
#define B00100010 34
|
||||
#define B100011 35
|
||||
#define B0100011 35
|
||||
#define B00100011 35
|
||||
#define B100100 36
|
||||
#define B0100100 36
|
||||
#define B00100100 36
|
||||
#define B100101 37
|
||||
#define B0100101 37
|
||||
#define B00100101 37
|
||||
#define B100110 38
|
||||
#define B0100110 38
|
||||
#define B00100110 38
|
||||
#define B100111 39
|
||||
#define B0100111 39
|
||||
#define B00100111 39
|
||||
#define B101000 40
|
||||
#define B0101000 40
|
||||
#define B00101000 40
|
||||
#define B101001 41
|
||||
#define B0101001 41
|
||||
#define B00101001 41
|
||||
#define B101010 42
|
||||
#define B0101010 42
|
||||
#define B00101010 42
|
||||
#define B101011 43
|
||||
#define B0101011 43
|
||||
#define B00101011 43
|
||||
#define B101100 44
|
||||
#define B0101100 44
|
||||
#define B00101100 44
|
||||
#define B101101 45
|
||||
#define B0101101 45
|
||||
#define B00101101 45
|
||||
#define B101110 46
|
||||
#define B0101110 46
|
||||
#define B00101110 46
|
||||
#define B101111 47
|
||||
#define B0101111 47
|
||||
#define B00101111 47
|
||||
#define B110000 48
|
||||
#define B0110000 48
|
||||
#define B00110000 48
|
||||
#define B110001 49
|
||||
#define B0110001 49
|
||||
#define B00110001 49
|
||||
#define B110010 50
|
||||
#define B0110010 50
|
||||
#define B00110010 50
|
||||
#define B110011 51
|
||||
#define B0110011 51
|
||||
#define B00110011 51
|
||||
#define B110100 52
|
||||
#define B0110100 52
|
||||
#define B00110100 52
|
||||
#define B110101 53
|
||||
#define B0110101 53
|
||||
#define B00110101 53
|
||||
#define B110110 54
|
||||
#define B0110110 54
|
||||
#define B00110110 54
|
||||
#define B110111 55
|
||||
#define B0110111 55
|
||||
#define B00110111 55
|
||||
#define B111000 56
|
||||
#define B0111000 56
|
||||
#define B00111000 56
|
||||
#define B111001 57
|
||||
#define B0111001 57
|
||||
#define B00111001 57
|
||||
#define B111010 58
|
||||
#define B0111010 58
|
||||
#define B00111010 58
|
||||
#define B111011 59
|
||||
#define B0111011 59
|
||||
#define B00111011 59
|
||||
#define B111100 60
|
||||
#define B0111100 60
|
||||
#define B00111100 60
|
||||
#define B111101 61
|
||||
#define B0111101 61
|
||||
#define B00111101 61
|
||||
#define B111110 62
|
||||
#define B0111110 62
|
||||
#define B00111110 62
|
||||
#define B111111 63
|
||||
#define B0111111 63
|
||||
#define B00111111 63
|
||||
#define B1000000 64
|
||||
#define B01000000 64
|
||||
#define B1000001 65
|
||||
#define B01000001 65
|
||||
#define B1000010 66
|
||||
#define B01000010 66
|
||||
#define B1000011 67
|
||||
#define B01000011 67
|
||||
#define B1000100 68
|
||||
#define B01000100 68
|
||||
#define B1000101 69
|
||||
#define B01000101 69
|
||||
#define B1000110 70
|
||||
#define B01000110 70
|
||||
#define B1000111 71
|
||||
#define B01000111 71
|
||||
#define B1001000 72
|
||||
#define B01001000 72
|
||||
#define B1001001 73
|
||||
#define B01001001 73
|
||||
#define B1001010 74
|
||||
#define B01001010 74
|
||||
#define B1001011 75
|
||||
#define B01001011 75
|
||||
#define B1001100 76
|
||||
#define B01001100 76
|
||||
#define B1001101 77
|
||||
#define B01001101 77
|
||||
#define B1001110 78
|
||||
#define B01001110 78
|
||||
#define B1001111 79
|
||||
#define B01001111 79
|
||||
#define B1010000 80
|
||||
#define B01010000 80
|
||||
#define B1010001 81
|
||||
#define B01010001 81
|
||||
#define B1010010 82
|
||||
#define B01010010 82
|
||||
#define B1010011 83
|
||||
#define B01010011 83
|
||||
#define B1010100 84
|
||||
#define B01010100 84
|
||||
#define B1010101 85
|
||||
#define B01010101 85
|
||||
#define B1010110 86
|
||||
#define B01010110 86
|
||||
#define B1010111 87
|
||||
#define B01010111 87
|
||||
#define B1011000 88
|
||||
#define B01011000 88
|
||||
#define B1011001 89
|
||||
#define B01011001 89
|
||||
#define B1011010 90
|
||||
#define B01011010 90
|
||||
#define B1011011 91
|
||||
#define B01011011 91
|
||||
#define B1011100 92
|
||||
#define B01011100 92
|
||||
#define B1011101 93
|
||||
#define B01011101 93
|
||||
#define B1011110 94
|
||||
#define B01011110 94
|
||||
#define B1011111 95
|
||||
#define B01011111 95
|
||||
#define B1100000 96
|
||||
#define B01100000 96
|
||||
#define B1100001 97
|
||||
#define B01100001 97
|
||||
#define B1100010 98
|
||||
#define B01100010 98
|
||||
#define B1100011 99
|
||||
#define B01100011 99
|
||||
#define B1100100 100
|
||||
#define B01100100 100
|
||||
#define B1100101 101
|
||||
#define B01100101 101
|
||||
#define B1100110 102
|
||||
#define B01100110 102
|
||||
#define B1100111 103
|
||||
#define B01100111 103
|
||||
#define B1101000 104
|
||||
#define B01101000 104
|
||||
#define B1101001 105
|
||||
#define B01101001 105
|
||||
#define B1101010 106
|
||||
#define B01101010 106
|
||||
#define B1101011 107
|
||||
#define B01101011 107
|
||||
#define B1101100 108
|
||||
#define B01101100 108
|
||||
#define B1101101 109
|
||||
#define B01101101 109
|
||||
#define B1101110 110
|
||||
#define B01101110 110
|
||||
#define B1101111 111
|
||||
#define B01101111 111
|
||||
#define B1110000 112
|
||||
#define B01110000 112
|
||||
#define B1110001 113
|
||||
#define B01110001 113
|
||||
#define B1110010 114
|
||||
#define B01110010 114
|
||||
#define B1110011 115
|
||||
#define B01110011 115
|
||||
#define B1110100 116
|
||||
#define B01110100 116
|
||||
#define B1110101 117
|
||||
#define B01110101 117
|
||||
#define B1110110 118
|
||||
#define B01110110 118
|
||||
#define B1110111 119
|
||||
#define B01110111 119
|
||||
#define B1111000 120
|
||||
#define B01111000 120
|
||||
#define B1111001 121
|
||||
#define B01111001 121
|
||||
#define B1111010 122
|
||||
#define B01111010 122
|
||||
#define B1111011 123
|
||||
#define B01111011 123
|
||||
#define B1111100 124
|
||||
#define B01111100 124
|
||||
#define B1111101 125
|
||||
#define B01111101 125
|
||||
#define B1111110 126
|
||||
#define B01111110 126
|
||||
#define B1111111 127
|
||||
#define B01111111 127
|
||||
#define B10000000 128
|
||||
#define B10000001 129
|
||||
#define B10000010 130
|
||||
#define B10000011 131
|
||||
#define B10000100 132
|
||||
#define B10000101 133
|
||||
#define B10000110 134
|
||||
#define B10000111 135
|
||||
#define B10001000 136
|
||||
#define B10001001 137
|
||||
#define B10001010 138
|
||||
#define B10001011 139
|
||||
#define B10001100 140
|
||||
#define B10001101 141
|
||||
#define B10001110 142
|
||||
#define B10001111 143
|
||||
#define B10010000 144
|
||||
#define B10010001 145
|
||||
#define B10010010 146
|
||||
#define B10010011 147
|
||||
#define B10010100 148
|
||||
#define B10010101 149
|
||||
#define B10010110 150
|
||||
#define B10010111 151
|
||||
#define B10011000 152
|
||||
#define B10011001 153
|
||||
#define B10011010 154
|
||||
#define B10011011 155
|
||||
#define B10011100 156
|
||||
#define B10011101 157
|
||||
#define B10011110 158
|
||||
#define B10011111 159
|
||||
#define B10100000 160
|
||||
#define B10100001 161
|
||||
#define B10100010 162
|
||||
#define B10100011 163
|
||||
#define B10100100 164
|
||||
#define B10100101 165
|
||||
#define B10100110 166
|
||||
#define B10100111 167
|
||||
#define B10101000 168
|
||||
#define B10101001 169
|
||||
#define B10101010 170
|
||||
#define B10101011 171
|
||||
#define B10101100 172
|
||||
#define B10101101 173
|
||||
#define B10101110 174
|
||||
#define B10101111 175
|
||||
#define B10110000 176
|
||||
#define B10110001 177
|
||||
#define B10110010 178
|
||||
#define B10110011 179
|
||||
#define B10110100 180
|
||||
#define B10110101 181
|
||||
#define B10110110 182
|
||||
#define B10110111 183
|
||||
#define B10111000 184
|
||||
#define B10111001 185
|
||||
#define B10111010 186
|
||||
#define B10111011 187
|
||||
#define B10111100 188
|
||||
#define B10111101 189
|
||||
#define B10111110 190
|
||||
#define B10111111 191
|
||||
#define B11000000 192
|
||||
#define B11000001 193
|
||||
#define B11000010 194
|
||||
#define B11000011 195
|
||||
#define B11000100 196
|
||||
#define B11000101 197
|
||||
#define B11000110 198
|
||||
#define B11000111 199
|
||||
#define B11001000 200
|
||||
#define B11001001 201
|
||||
#define B11001010 202
|
||||
#define B11001011 203
|
||||
#define B11001100 204
|
||||
#define B11001101 205
|
||||
#define B11001110 206
|
||||
#define B11001111 207
|
||||
#define B11010000 208
|
||||
#define B11010001 209
|
||||
#define B11010010 210
|
||||
#define B11010011 211
|
||||
#define B11010100 212
|
||||
#define B11010101 213
|
||||
#define B11010110 214
|
||||
#define B11010111 215
|
||||
#define B11011000 216
|
||||
#define B11011001 217
|
||||
#define B11011010 218
|
||||
#define B11011011 219
|
||||
#define B11011100 220
|
||||
#define B11011101 221
|
||||
#define B11011110 222
|
||||
#define B11011111 223
|
||||
#define B11100000 224
|
||||
#define B11100001 225
|
||||
#define B11100010 226
|
||||
#define B11100011 227
|
||||
#define B11100100 228
|
||||
#define B11100101 229
|
||||
#define B11100110 230
|
||||
#define B11100111 231
|
||||
#define B11101000 232
|
||||
#define B11101001 233
|
||||
#define B11101010 234
|
||||
#define B11101011 235
|
||||
#define B11101100 236
|
||||
#define B11101101 237
|
||||
#define B11101110 238
|
||||
#define B11101111 239
|
||||
#define B11110000 240
|
||||
#define B11110001 241
|
||||
#define B11110010 242
|
||||
#define B11110011 243
|
||||
#define B11110100 244
|
||||
#define B11110101 245
|
||||
#define B11110110 246
|
||||
#define B11110111 247
|
||||
#define B11111000 248
|
||||
#define B11111001 249
|
||||
#define B11111010 250
|
||||
#define B11111011 251
|
||||
#define B11111100 252
|
||||
#define B11111101 253
|
||||
#define B11111110 254
|
||||
#define B11111111 255
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <WProgram.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
setup();
|
||||
|
||||
for (;;)
|
||||
loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
pins_arduino.c - pin definitions for the Arduino board
|
||||
Part of Arduino / Wiring Lite
|
||||
|
||||
Copyright (c) 2005 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: pins_arduino.c 254 2007-04-20 23:17:38Z mellis $
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
// On the Sanguino board, digital pins are also used
|
||||
// for the analog output (software PWM). Analog input
|
||||
// pins are a separate set.
|
||||
|
||||
// ATMEL ATMEGA644P / SANGUINO
|
||||
//
|
||||
// +---\/---+
|
||||
// INT0 (D 0) PB0 1| |40 PA0 (AI 0 / D31)
|
||||
// INT1 (D 1) PB1 2| |39 PA1 (AI 1 / D30)
|
||||
// INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
|
||||
// PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
|
||||
// PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
|
||||
// MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
|
||||
// MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
|
||||
// SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
|
||||
// RST 9| |32 AREF
|
||||
// VCC 10| |31 GND
|
||||
// GND 11| |30 AVCC
|
||||
// XTAL2 12| |29 PC7 (D 23)
|
||||
// XTAL1 13| |28 PC6 (D 22)
|
||||
// RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
|
||||
// TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
|
||||
// RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
|
||||
// TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
|
||||
// PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
|
||||
// PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
|
||||
// PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
|
||||
// +--------+
|
||||
//
|
||||
|
||||
#define PA 1
|
||||
#define PB 2
|
||||
#define PC 3
|
||||
#define PD 4
|
||||
|
||||
// these arrays map port names (e.g. port B) to the
|
||||
// appropriate addresses for various functions (e.g. reading
|
||||
// and writing)
|
||||
const uint8_t PROGMEM port_to_mode_PGM[] =
|
||||
{
|
||||
NOT_A_PORT,
|
||||
&DDRA,
|
||||
&DDRB,
|
||||
&DDRC,
|
||||
&DDRD,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM port_to_output_PGM[] =
|
||||
{
|
||||
NOT_A_PORT,
|
||||
&PORTA,
|
||||
&PORTB,
|
||||
&PORTC,
|
||||
&PORTD,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM port_to_input_PGM[] =
|
||||
{
|
||||
NOT_A_PORT,
|
||||
&PINA,
|
||||
&PINB,
|
||||
&PINC,
|
||||
&PIND,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
|
||||
{
|
||||
PB, /* 0 */
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PD, /* 8 */
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PC, /* 16 */
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PA, /* 24 */
|
||||
PA,
|
||||
PA,
|
||||
PA,
|
||||
PA,
|
||||
PA,
|
||||
PA,
|
||||
PA /* 31 */
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
|
||||
{
|
||||
_BV(0), /* 0, port B */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(0), /* 8, port D */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(0), /* 16, port C */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(7), /* 24, port A */
|
||||
_BV(6),
|
||||
_BV(5),
|
||||
_BV(4),
|
||||
_BV(3),
|
||||
_BV(2),
|
||||
_BV(1),
|
||||
_BV(0)
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
|
||||
{
|
||||
NOT_ON_TIMER, /* 0 - PB0 */
|
||||
NOT_ON_TIMER, /* 1 - PB1 */
|
||||
NOT_ON_TIMER, /* 2 - PB2 */
|
||||
TIMER0A, /* 3 - PB3 */
|
||||
TIMER0B, /* 4 - PB4 */
|
||||
NOT_ON_TIMER, /* 5 - PB5 */
|
||||
NOT_ON_TIMER, /* 6 - PB6 */
|
||||
NOT_ON_TIMER, /* 7 - PB7 */
|
||||
NOT_ON_TIMER, /* 8 - PD0 */
|
||||
NOT_ON_TIMER, /* 9 - PD1 */
|
||||
NOT_ON_TIMER, /* 10 - PD2 */
|
||||
NOT_ON_TIMER, /* 11 - PD3 */
|
||||
TIMER1B, /* 12 - PD4 */
|
||||
TIMER1A, /* 13 - PD5 */
|
||||
TIMER2B, /* 14 - PD6 */
|
||||
TIMER2A, /* 15 - PD7 */
|
||||
NOT_ON_TIMER, /* 16 - PC0 */
|
||||
NOT_ON_TIMER, /* 17 - PC1 */
|
||||
NOT_ON_TIMER, /* 18 - PC2 */
|
||||
NOT_ON_TIMER, /* 19 - PC3 */
|
||||
NOT_ON_TIMER, /* 20 - PC4 */
|
||||
NOT_ON_TIMER, /* 21 - PC5 */
|
||||
NOT_ON_TIMER, /* 22 - PC6 */
|
||||
NOT_ON_TIMER, /* 23 - PC7 */
|
||||
NOT_ON_TIMER, /* 24 - PA0 */
|
||||
NOT_ON_TIMER, /* 25 - PA1 */
|
||||
NOT_ON_TIMER, /* 26 - PA2 */
|
||||
NOT_ON_TIMER, /* 27 - PA3 */
|
||||
NOT_ON_TIMER, /* 28 - PA4 */
|
||||
NOT_ON_TIMER, /* 29 - PA5 */
|
||||
NOT_ON_TIMER, /* 30 - PA6 */
|
||||
NOT_ON_TIMER /* 31 - PA7 */
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
pins_arduino.h - Pin definition functions for Arduino
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT 0
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
#define TIMER0A 1
|
||||
#define TIMER0B 2
|
||||
#define TIMER1A 3
|
||||
#define TIMER1B 4
|
||||
#define TIMER2 5
|
||||
#define TIMER2A 6
|
||||
#define TIMER2B 7
|
||||
|
||||
extern const uint8_t PROGMEM port_to_mode_PGM[];
|
||||
extern const uint8_t PROGMEM port_to_input_PGM[];
|
||||
extern const uint8_t PROGMEM port_to_output_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
//
|
||||
// These perform slightly better as macros compared to inline functions
|
||||
//
|
||||
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
|
||||
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
|
||||
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
|
||||
#define analogInPinToBit(P) (P)
|
||||
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
|
||||
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
|
||||
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_mode_PGM + (P))) )
|
||||
|
||||
#endif
|
||||
@@ -19,48 +19,104 @@
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.c 388 2008-03-08 22:05:23Z mellis $
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
|
||||
// the overflow handler is called every 256 ticks.
|
||||
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
|
||||
|
||||
// the whole number of milliseconds per timer0 overflow
|
||||
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
|
||||
|
||||
// the fractional number of milliseconds per timer0 overflow. we shift right
|
||||
// by three to fit these numbers into a byte. (for the clock speeds we care
|
||||
// about - 8 and 16 MHz - this doesn't lose precision.)
|
||||
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
|
||||
#define FRACT_MAX (1000 >> 3)
|
||||
|
||||
volatile unsigned long timer0_overflow_count = 0;
|
||||
volatile unsigned long timer0_millis = 0;
|
||||
static unsigned char timer0_fract = 0;
|
||||
|
||||
SIGNAL(TIMER0_OVF_vect)
|
||||
{
|
||||
// timer 0 prescale factor is 64 and the timer overflows at 256
|
||||
timer0_millis++;
|
||||
// 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;
|
||||
}
|
||||
|
||||
timer0_fract = f;
|
||||
timer0_millis = m;
|
||||
timer0_overflow_count++;
|
||||
}
|
||||
|
||||
unsigned long millis()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
|
||||
// disable interrupts while we read timer0_millis or we might get an
|
||||
// inconsistent value (e.g. in the middle of the timer0_millis++)
|
||||
// inconsistent value (e.g. in the middle of a write to timer0_millis)
|
||||
cli();
|
||||
m = timer0_millis;
|
||||
SREG = oldSREG;
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
unsigned long micros() {
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG, t;
|
||||
|
||||
cli();
|
||||
m = timer0_overflow_count;
|
||||
#if defined(TCNT0)
|
||||
t = TCNT0;
|
||||
#elif defined(TCNT0L)
|
||||
t = TCNT0L;
|
||||
#else
|
||||
#error TIMER 0 not defined
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TIFR0
|
||||
if ((TIFR0 & _BV(TOV0)) && (t < 255))
|
||||
m++;
|
||||
#else
|
||||
if ((TIFR & _BV(TOV0)) && (t < 255))
|
||||
m++;
|
||||
#endif
|
||||
|
||||
SREG = oldSREG;
|
||||
|
||||
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
unsigned long start = millis();
|
||||
|
||||
while (millis() - start <= ms)
|
||||
;
|
||||
uint16_t start = (uint16_t)micros();
|
||||
|
||||
while (ms > 0) {
|
||||
if (((uint16_t)micros() - start) >= 1000) {
|
||||
ms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock.
|
||||
* Disables interrupts, which will disrupt the millis() function if used
|
||||
* too frequently. */
|
||||
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
uint8_t oldSREG;
|
||||
|
||||
// calling avrlib's delay_us() function with low values (e.g. 1 or
|
||||
// 2 microseconds) gives delays longer than desired.
|
||||
//delay_us(us);
|
||||
@@ -95,25 +151,17 @@ void delayMicroseconds(unsigned int us)
|
||||
// per iteration, so execute it twice for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 1;
|
||||
|
||||
|
||||
// partially compensate for the time taken by the preceeding commands.
|
||||
// we can't subtract any more than this or we'd overflow w/ small delays.
|
||||
us--;
|
||||
#endif
|
||||
|
||||
// disable interrupts, otherwise the timer 0 overflow interrupt that
|
||||
// tracks milliseconds will make us delay longer than we want.
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
|
||||
// busy wait
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
|
||||
// reenable interrupts.
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
void init()
|
||||
@@ -125,34 +173,99 @@ void init()
|
||||
// on the ATmega168, timer 0 is also used for fast hardware pwm
|
||||
// (using phase-correct PWM would mean that timer 0 overflowed half as often
|
||||
// resulting in different millis() behavior on the ATmega8 and ATmega168)
|
||||
#if defined(TCCR0A) && defined(WGM01)
|
||||
sbi(TCCR0A, WGM01);
|
||||
sbi(TCCR0A, WGM00);
|
||||
#endif
|
||||
|
||||
// set timer 0 prescale factor to 64
|
||||
#if defined(__AVR_ATmega128__)
|
||||
// CPU specific: different values for the ATmega128
|
||||
sbi(TCCR0, CS02);
|
||||
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the standard atmega8
|
||||
sbi(TCCR0, CS01);
|
||||
sbi(TCCR0, CS00);
|
||||
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the standard 168/328/1280/2560
|
||||
sbi(TCCR0B, CS01);
|
||||
sbi(TCCR0B, CS00);
|
||||
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the __AVR_ATmega645__ series
|
||||
sbi(TCCR0A, CS01);
|
||||
sbi(TCCR0A, CS00);
|
||||
#else
|
||||
#error Timer 0 prescale factor 64 not set correctly
|
||||
#endif
|
||||
|
||||
// enable timer 0 overflow interrupt
|
||||
#if defined(TIMSK) && defined(TOIE0)
|
||||
sbi(TIMSK, TOIE0);
|
||||
#elif defined(TIMSK0) && defined(TOIE0)
|
||||
sbi(TIMSK0, TOIE0);
|
||||
#else
|
||||
#error Timer 0 overflow interrupt not set correctly
|
||||
#endif
|
||||
|
||||
// timers 1 and 2 are used for phase-correct hardware pwm
|
||||
// this is better for motors as it ensures an even waveform
|
||||
// note, however, that fast pwm mode can achieve a frequency of up
|
||||
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
|
||||
#if 0
|
||||
|
||||
TCCR1B = 0;
|
||||
|
||||
// set timer 1 prescale factor to 64
|
||||
#if defined(TCCR1B) && defined(CS11) && defined(CS10)
|
||||
sbi(TCCR1B, CS11);
|
||||
sbi(TCCR1B, CS10);
|
||||
|
||||
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
|
||||
sbi(TCCR1, CS11);
|
||||
sbi(TCCR1, CS10);
|
||||
#endif
|
||||
// put timer 1 in 8-bit phase correct pwm mode
|
||||
#if defined(TCCR1A) && defined(WGM10)
|
||||
sbi(TCCR1A, WGM10);
|
||||
#elif defined(TCCR1)
|
||||
#warning this needs to be finished
|
||||
#endif
|
||||
|
||||
// set timer 2 prescale factor to 64
|
||||
#if defined(TCCR2) && defined(CS22)
|
||||
sbi(TCCR2, CS22);
|
||||
#elif defined(TCCR2B) && defined(CS22)
|
||||
sbi(TCCR2B, CS22);
|
||||
#else
|
||||
#warning Timer 2 not finished (may not be present on this CPU)
|
||||
#endif
|
||||
|
||||
// configure timer 2 for phase correct pwm (8-bit)
|
||||
#if defined(TCCR2) && defined(WGM20)
|
||||
sbi(TCCR2, WGM20);
|
||||
#elif defined(TCCR2A) && defined(WGM20)
|
||||
sbi(TCCR2A, WGM20);
|
||||
#else
|
||||
#warning Timer 2 not finished (may not be present on this CPU)
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
|
||||
sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
|
||||
sbi(TCCR3B, CS30);
|
||||
sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
|
||||
sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
|
||||
sbi(TCCR4B, CS40);
|
||||
sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
|
||||
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
|
||||
sbi(TCCR5B, CS50);
|
||||
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
|
||||
#if defined(ADCSRA)
|
||||
// set a2d prescale factor to 128
|
||||
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
|
||||
// XXX: this will not work properly for other clock speeds, and
|
||||
@@ -163,14 +276,14 @@ void init()
|
||||
|
||||
// enable a2d conversions
|
||||
sbi(ADCSRA, ADEN);
|
||||
#endif
|
||||
|
||||
// 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()
|
||||
#if defined(UCSRB)
|
||||
UCSRB = 0;
|
||||
#elif defined(UCSR0B)
|
||||
UCSR0B = 0;
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
//TODO: test to see if disabling this helps?
|
||||
//UCSR1B = 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
wiring.h - Partial implementation of the Wiring API for the ATmega8.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef Wiring_h
|
||||
#define Wiring_h
|
||||
|
||||
#include <math.h>
|
||||
#include <avr/io.h>
|
||||
#include <stdlib.h>
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
|
||||
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
void digitalWrite(uint8_t, uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(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 setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
wiring_analog.c - analog input and output
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
uint8_t analog_reference = DEFAULT;
|
||||
|
||||
void analogReference(uint8_t mode)
|
||||
{
|
||||
// can't actually set the register here because the default setting
|
||||
// will connect AVCC and the AREF pin, which would cause a short if
|
||||
// there's something connected to AREF.
|
||||
analog_reference = mode;
|
||||
}
|
||||
|
||||
int analogRead(uint8_t pin)
|
||||
{
|
||||
uint8_t low, high;
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
|
||||
#else
|
||||
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
|
||||
#endif
|
||||
|
||||
#if defined(ADCSRB) && defined(MUX5)
|
||||
// the MUX5 bit of ADCSRB selects whether we're reading from channels
|
||||
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
|
||||
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
|
||||
#endif
|
||||
|
||||
// set the analog reference (high two bits of ADMUX) and select the
|
||||
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
|
||||
// to 0 (the default).
|
||||
#if defined(ADMUX)
|
||||
ADMUX = (analog_reference << 6) | (pin & 0x07);
|
||||
#endif
|
||||
|
||||
// without a delay, we seem to read from the wrong channel
|
||||
//delay(1);
|
||||
|
||||
#if defined(ADCSRA) && defined(ADCL)
|
||||
// start the conversion
|
||||
sbi(ADCSRA, ADSC);
|
||||
|
||||
// ADSC is cleared when the conversion finishes
|
||||
while (bit_is_set(ADCSRA, ADSC));
|
||||
|
||||
// we have to read ADCL first; doing so locks both ADCL
|
||||
// and ADCH until ADCH is read. reading ADCL second would
|
||||
// cause the results of each conversion to be discarded,
|
||||
// as ADCL and ADCH would be locked when it completed.
|
||||
low = ADCL;
|
||||
high = ADCH;
|
||||
#else
|
||||
// we dont have an ADC, return 0
|
||||
low = 0;
|
||||
high = 0;
|
||||
#endif
|
||||
|
||||
// combine the two bytes
|
||||
return (high << 8) | low;
|
||||
}
|
||||
|
||||
// Right now, PWM output only works on the pins with
|
||||
// hardware support. These are defined in the appropriate
|
||||
// pins_*.c file. For the rest of the pins, we default
|
||||
// to digital output.
|
||||
void analogWrite(uint8_t pin, int val)
|
||||
{
|
||||
// We need to make sure the PWM output is enabled for those pins
|
||||
// that support it, as we turn it off when digitally reading or
|
||||
// writing with them. Also, make sure the pin is in output mode
|
||||
// for consistenty with Wiring, which doesn't require a pinMode
|
||||
// call for the analog output pins.
|
||||
pinMode(pin, OUTPUT);
|
||||
if (val == 0)
|
||||
{
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
else if (val == 255)
|
||||
{
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(digitalPinToTimer(pin))
|
||||
{
|
||||
// XXX fix needed for atmega8
|
||||
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
|
||||
case TIMER0A:
|
||||
// connect pwm to pin on timer 0
|
||||
sbi(TCCR0, COM00);
|
||||
OCR0 = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
case TIMER0A:
|
||||
// connect pwm to pin on timer 0, channel A
|
||||
sbi(TCCR0A, COM0A1);
|
||||
OCR0A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0B1)
|
||||
case TIMER0B:
|
||||
// connect pwm to pin on timer 0, channel B
|
||||
sbi(TCCR0A, COM0B1);
|
||||
OCR0B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
case TIMER1A:
|
||||
// connect pwm to pin on timer 1, channel A
|
||||
sbi(TCCR1A, COM1A1);
|
||||
OCR1A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1B1)
|
||||
case TIMER1B:
|
||||
// connect pwm to pin on timer 1, channel B
|
||||
sbi(TCCR1A, COM1B1);
|
||||
OCR1B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2) && defined(COM21)
|
||||
case TIMER2:
|
||||
// connect pwm to pin on timer 2
|
||||
sbi(TCCR2, COM21);
|
||||
OCR2 = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
case TIMER2A:
|
||||
// connect pwm to pin on timer 2, channel A
|
||||
sbi(TCCR2A, COM2A1);
|
||||
OCR2A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2B1)
|
||||
case TIMER2B:
|
||||
// connect pwm to pin on timer 2, channel B
|
||||
sbi(TCCR2A, COM2B1);
|
||||
OCR2B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
case TIMER3A:
|
||||
// connect pwm to pin on timer 3, channel A
|
||||
sbi(TCCR3A, COM3A1);
|
||||
OCR3A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3B1)
|
||||
case TIMER3B:
|
||||
// connect pwm to pin on timer 3, channel B
|
||||
sbi(TCCR3A, COM3B1);
|
||||
OCR3B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3C1)
|
||||
case TIMER3C:
|
||||
// connect pwm to pin on timer 3, channel C
|
||||
sbi(TCCR3A, COM3C1);
|
||||
OCR3C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4A1)
|
||||
case TIMER4A:
|
||||
// connect pwm to pin on timer 4, channel A
|
||||
sbi(TCCR4A, COM4A1);
|
||||
OCR4A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4B1)
|
||||
case TIMER4B:
|
||||
// connect pwm to pin on timer 4, channel B
|
||||
sbi(TCCR4A, COM4B1);
|
||||
OCR4B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4C1)
|
||||
case TIMER4C:
|
||||
// connect pwm to pin on timer 4, channel C
|
||||
sbi(TCCR4A, COM4C1);
|
||||
OCR4C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
case TIMER5A:
|
||||
// connect pwm to pin on timer 5, channel A
|
||||
sbi(TCCR5A, COM5A1);
|
||||
OCR5A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5B1)
|
||||
case TIMER5B:
|
||||
// connect pwm to pin on timer 5, channel B
|
||||
sbi(TCCR5A, COM5B1);
|
||||
OCR5B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5C1)
|
||||
case TIMER5C:
|
||||
// connect pwm to pin on timer 5, channel C
|
||||
sbi(TCCR5A, COM5C1);
|
||||
OCR5C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NOT_ON_TIMER:
|
||||
default:
|
||||
if (val < 128) {
|
||||
digitalWrite(pin, LOW);
|
||||
} else {
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
wiring_digital.c - digital input and output functions
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
volatile uint8_t *reg;
|
||||
|
||||
if (port == NOT_A_PIN) return;
|
||||
|
||||
// JWS: can I let the optimizer do this?
|
||||
reg = portModeRegister(port);
|
||||
|
||||
if (mode == INPUT) {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*reg &= ~bit;
|
||||
SREG = oldSREG;
|
||||
} else {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*reg |= bit;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
}
|
||||
|
||||
// Forcing this inline keeps the callers from having to push their own stuff
|
||||
// on the stack. It is a good performance win and only takes 1 more byte per
|
||||
// user than calling. (It will take more bytes on the 168.)
|
||||
//
|
||||
// But shouldn't this be moved into pinMode? Seems silly to check and do on
|
||||
// each digitalread or write.
|
||||
//
|
||||
// Mark Sproul:
|
||||
// - Removed inline. Save 170 bytes on atmega1280
|
||||
// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
|
||||
// - Added more #ifdefs, now compiles for atmega645
|
||||
//
|
||||
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
|
||||
//static inline void turnOffPWM(uint8_t timer)
|
||||
static void turnOffPWM(uint8_t timer)
|
||||
{
|
||||
switch (timer)
|
||||
{
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
case TIMER1A: cbi(TCCR1A, COM1A1); break;
|
||||
#endif
|
||||
#if defined(TCCR1A) && defined(COM1B1)
|
||||
case TIMER1B: cbi(TCCR1A, COM1B1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2) && defined(COM21)
|
||||
case TIMER2: cbi(TCCR2, COM21); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
case TIMER0A: cbi(TCCR0A, COM0A1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMER0B) && defined(COM0B1)
|
||||
case TIMER0B: cbi(TCCR0A, COM0B1); break;
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
case TIMER2A: cbi(TCCR2A, COM2A1); break;
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(COM2B1)
|
||||
case TIMER2B: cbi(TCCR2A, COM2B1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
case TIMER3A: cbi(TCCR3A, COM3A1); break;
|
||||
#endif
|
||||
#if defined(TCCR3A) && defined(COM3B1)
|
||||
case TIMER3B: cbi(TCCR3A, COM3B1); break;
|
||||
#endif
|
||||
#if defined(TCCR3A) && defined(COM3C1)
|
||||
case TIMER3C: cbi(TCCR3A, COM3C1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4A1)
|
||||
case TIMER4A: cbi(TCCR4A, COM4A1); break;
|
||||
#endif
|
||||
#if defined(TCCR4A) && defined(COM4B1)
|
||||
case TIMER4B: cbi(TCCR4A, COM4B1); break;
|
||||
#endif
|
||||
#if defined(TCCR4A) && defined(COM4C1)
|
||||
case TIMER4C: cbi(TCCR4A, COM4C1); break;
|
||||
#endif
|
||||
#if defined(TCCR5A)
|
||||
case TIMER5A: cbi(TCCR5A, COM5A1); break;
|
||||
case TIMER5B: cbi(TCCR5A, COM5B1); break;
|
||||
case TIMER5C: cbi(TCCR5A, COM5C1); break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
uint8_t timer = digitalPinToTimer(pin);
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
volatile uint8_t *out;
|
||||
|
||||
if (port == NOT_A_PIN) return;
|
||||
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before doing a digital write.
|
||||
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
|
||||
|
||||
out = portOutputRegister(port);
|
||||
|
||||
if (val == LOW) {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*out &= ~bit;
|
||||
SREG = oldSREG;
|
||||
} else {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*out |= bit;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
}
|
||||
|
||||
int digitalRead(uint8_t pin)
|
||||
{
|
||||
uint8_t timer = digitalPinToTimer(pin);
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
|
||||
if (port == NOT_A_PIN) return LOW;
|
||||
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before getting a digital reading.
|
||||
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
|
||||
|
||||
if (*portInputRegister(port) & bit) return HIGH;
|
||||
return LOW;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
wiring_private.h - Internal header file.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef WiringPrivate_h
|
||||
#define WiringPrivate_h
|
||||
#include <math.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/delay.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wiring.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
#define EXTERNAL_INT_0 0
|
||||
#define EXTERNAL_INT_1 1
|
||||
#define EXTERNAL_INT_2 2
|
||||
#define EXTERNAL_INT_3 3
|
||||
#define EXTERNAL_INT_4 4
|
||||
#define EXTERNAL_INT_5 5
|
||||
#define EXTERNAL_INT_6 6
|
||||
#define EXTERNAL_INT_7 7
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 8
|
||||
#else
|
||||
#define EXTERNAL_NUM_INTERRUPTS 2
|
||||
#endif
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
wiring_pulse.c - pulseIn() function
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
|
||||
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
|
||||
* to 3 minutes in length, but must be called at least a few dozen microseconds
|
||||
* before the start of the pulse. */
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
{
|
||||
// cache the port and bit of the pin in order to speed up the
|
||||
// pulse width measuring loop and achieve finer resolution. calling
|
||||
// digitalRead() instead yields much coarser resolution.
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
uint8_t stateMask = (state ? bit : 0);
|
||||
unsigned long width = 0; // keep initialization out of time critical area
|
||||
|
||||
// convert the timeout from microseconds to a number of times through
|
||||
// the initial loop; it takes 16 clock cycles per iteration.
|
||||
unsigned long numloops = 0;
|
||||
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
|
||||
|
||||
// wait for any previous pulse to end
|
||||
while ((*portInputRegister(port) & bit) == stateMask)
|
||||
if (numloops++ == maxloops)
|
||||
return 0;
|
||||
|
||||
// wait for the pulse to start
|
||||
while ((*portInputRegister(port) & bit) != stateMask)
|
||||
if (numloops++ == maxloops)
|
||||
return 0;
|
||||
|
||||
// wait for the pulse to stop
|
||||
while ((*portInputRegister(port) & bit) == stateMask) {
|
||||
if (numloops++ == maxloops)
|
||||
return 0;
|
||||
width++;
|
||||
}
|
||||
|
||||
// convert the reading to microseconds. The loop has been determined
|
||||
// to be 20 clock cycles long and have about 16 clocks between the edge
|
||||
// and the start of the loop. There will be some error introduced by
|
||||
// the interrupt handlers.
|
||||
return clockCyclesToMicroseconds(width * 21 + 16);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
wiring_shift.c - shiftOut() function
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
digitalWrite(clockPin, HIGH);
|
||||
if (bitOrder == LSBFIRST)
|
||||
value |= digitalRead(dataPin) << i;
|
||||
else
|
||||
value |= digitalRead(dataPin) << (7 - i);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
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))));
|
||||
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
avrisp.name=AVR ISP
|
||||
avrisp.communication=serial
|
||||
avrisp.protocol=stk500v1
|
||||
|
||||
avrispmkii.name=AVRISP mkII
|
||||
avrispmkii.communication=usb
|
||||
avrispmkii.protocol=stk500v2
|
||||
|
||||
usbtinyisp.name=USBtinyISP
|
||||
usbtinyisp.protocol=usbtiny
|
||||
|
||||
parallel.name=Parallel Programmer
|
||||
parallel.protocol=dapa
|
||||
parallel.force=true
|
||||
# parallel.delay=200
|
||||
|
||||
arduinoisp.name=Arduino as ISP
|
||||
arduinoisp.communication=serial
|
||||
arduinoisp.protocol=stk500v1
|
||||
arduinoisp.speed=19200
|
||||
+643
-643
File diff suppressed because it is too large
Load Diff
+241
-233
@@ -1,233 +1,241 @@
|
||||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Sd2Card_h
|
||||
#define Sd2Card_h
|
||||
/**
|
||||
* \file
|
||||
* Sd2Card class
|
||||
*/
|
||||
#include "Sd2PinMap.h"
|
||||
#include "SdInfo.h"
|
||||
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_FULL_SPEED = 0;
|
||||
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_HALF_SPEED = 1;
|
||||
/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_QUARTER_SPEED = 2;
|
||||
/**
|
||||
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
|
||||
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||
*
|
||||
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||
* but many SD cards will fail with GPS Shield V1.0.
|
||||
*/
|
||||
#define MEGA_SOFT_SPI 0
|
||||
//------------------------------------------------------------------------------
|
||||
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
|
||||
#define SOFTWARE_SPI
|
||||
#endif // MEGA_SOFT_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
// SPI pin definitions
|
||||
//
|
||||
#ifndef SOFTWARE_SPI
|
||||
// hardware pin defs
|
||||
/**
|
||||
* SD Chip Select pin
|
||||
*
|
||||
* Warning if this pin is redefined the hardware SS will pin will be enabled
|
||||
* as an output by init(). An avr processor will not function as an SPI
|
||||
* master unless SS is set to output mode.
|
||||
*/
|
||||
/** The default chip select pin for the SD card is SS. */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
|
||||
// The following three pins must not be redefined for hardware SPI.
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = MOSI_PIN;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = MISO_PIN;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = SCK_PIN;
|
||||
/** optimize loops for hardware SPI */
|
||||
#define OPTIMIZE_HARDWARE_SPI
|
||||
|
||||
#else // SOFTWARE_SPI
|
||||
// define software SPI pins so Mega can use unmodified GPS Shield
|
||||
/** SPI chip select pin */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = 10;
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = 11;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = 12;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = 13;
|
||||
#endif // SOFTWARE_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
/** Protect block zero from write if nonzero */
|
||||
#define SD_PROTECT_BLOCK_ZERO 1
|
||||
/** init timeout ms */
|
||||
uint16_t const SD_INIT_TIMEOUT = 2000;
|
||||
/** erase timeout ms */
|
||||
uint16_t const SD_ERASE_TIMEOUT = 10000;
|
||||
/** read timeout ms */
|
||||
uint16_t const SD_READ_TIMEOUT = 300;
|
||||
/** write time out ms */
|
||||
uint16_t const SD_WRITE_TIMEOUT = 600;
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card errors
|
||||
/** timeout error for command CMD0 */
|
||||
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
|
||||
/** CMD8 was not accepted - not a valid SD card*/
|
||||
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
|
||||
/** card returned an error response for CMD17 (read block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
|
||||
/** card returned an error response for CMD24 (write block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
|
||||
/** WRITE_MULTIPLE_BLOCKS command failed */
|
||||
uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
|
||||
/** card returned an error response for CMD58 (read OCR) */
|
||||
uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
|
||||
/** SET_WR_BLK_ERASE_COUNT failed */
|
||||
uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
|
||||
/** card's ACMD41 initialization process timeout */
|
||||
uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
|
||||
/** card returned a bad CSR version field */
|
||||
uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
|
||||
/** erase block group command failed */
|
||||
uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
|
||||
/** card not capable of single block erase */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
|
||||
/** Erase sequence timed out */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
|
||||
/** card returned an error token instead of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ = 0X0D;
|
||||
/** read CID or CSD failed */
|
||||
uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
|
||||
/** timeout while waiting for start of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
|
||||
/** card did not accept STOP_TRAN_TOKEN */
|
||||
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
|
||||
/** card returned an error token as a response to a write operation */
|
||||
uint8_t const SD_CARD_ERROR_WRITE = 0X11;
|
||||
/** attempt to write protected block zero */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
|
||||
/** card did not go ready for a multiple block write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
|
||||
/** card returned an error to a CMD13 status check after a write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
|
||||
/** timeout occurred during write programming */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
|
||||
/** incorrect rate selected */
|
||||
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
|
||||
//------------------------------------------------------------------------------
|
||||
// card types
|
||||
/** Standard capacity V1 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD1 = 1;
|
||||
/** Standard capacity V2 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD2 = 2;
|
||||
/** High Capacity SD card */
|
||||
uint8_t const SD_CARD_TYPE_SDHC = 3;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class Sd2Card
|
||||
* \brief Raw access to SD and SDHC flash memory cards.
|
||||
*/
|
||||
class Sd2Card {
|
||||
public:
|
||||
/** Construct an instance of Sd2Card. */
|
||||
Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
|
||||
uint32_t cardSize(void);
|
||||
uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||
uint8_t eraseSingleBlockEnable(void);
|
||||
/**
|
||||
* \return error code for last error. See Sd2Card.h for a list of error codes.
|
||||
*/
|
||||
uint8_t errorCode(void) const {return errorCode_;}
|
||||
/** \return error data for last error. */
|
||||
uint8_t errorData(void) const {return status_;}
|
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip
|
||||
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*/
|
||||
uint8_t init(void) {
|
||||
return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
|
||||
}
|
||||
/**
|
||||
* Initialize an SD flash memory card with the selected SPI clock rate
|
||||
* and the default SD chip select pin.
|
||||
* See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*/
|
||||
uint8_t init(uint8_t sckRateID) {
|
||||
return init(sckRateID, SD_CHIP_SELECT_PIN);
|
||||
}
|
||||
uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin);
|
||||
void partialBlockRead(uint8_t value);
|
||||
/** Returns the current value, true or false, for partial block read. */
|
||||
uint8_t partialBlockRead(void) const {return partialBlockRead_;}
|
||||
uint8_t readBlock(uint32_t block, uint8_t* dst);
|
||||
uint8_t readData(uint32_t block,
|
||||
uint16_t offset, uint16_t count, uint8_t* dst);
|
||||
/**
|
||||
* Read a cards CID register. The CID contains card identification
|
||||
* information such as Manufacturer ID, Product name, Product serial
|
||||
* number and Manufacturing date. */
|
||||
uint8_t readCID(cid_t* cid) {
|
||||
return readRegister(CMD10, cid);
|
||||
}
|
||||
/**
|
||||
* Read a cards CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents. */
|
||||
uint8_t readCSD(csd_t* csd) {
|
||||
return readRegister(CMD9, csd);
|
||||
}
|
||||
void readEnd(void);
|
||||
uint8_t setSckRate(uint8_t sckRateID);
|
||||
/** Return the card type: SD V1, SD V2 or SDHC */
|
||||
uint8_t type(void) const {return type_;}
|
||||
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
|
||||
uint8_t writeData(const uint8_t* src);
|
||||
uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||
uint8_t writeStop(void);
|
||||
private:
|
||||
uint32_t block_;
|
||||
uint8_t chipSelectPin_;
|
||||
uint8_t errorCode_;
|
||||
uint8_t inBlock_;
|
||||
uint16_t offset_;
|
||||
uint8_t partialBlockRead_;
|
||||
uint8_t status_;
|
||||
uint8_t type_;
|
||||
// private functions
|
||||
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||
cardCommand(CMD55, 0);
|
||||
return cardCommand(cmd, arg);
|
||||
}
|
||||
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||
void error(uint8_t code) {errorCode_ = code;}
|
||||
uint8_t readRegister(uint8_t cmd, void* buf);
|
||||
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
|
||||
void chipSelectHigh(void);
|
||||
void chipSelectLow(void);
|
||||
void type(uint8_t value) {type_ = value;}
|
||||
uint8_t waitNotBusy(uint16_t timeoutMillis);
|
||||
uint8_t writeData(uint8_t token, const uint8_t* src);
|
||||
uint8_t waitStartBlock(void);
|
||||
};
|
||||
#endif // Sd2Card_h
|
||||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef Sd2Card_h
|
||||
#define Sd2Card_h
|
||||
/**
|
||||
* \file
|
||||
* \brief Sd2Card class for V2 SD/SDHC cards
|
||||
*/
|
||||
#include "SdFatConfig.h"
|
||||
#include "Sd2PinMap.h"
|
||||
#include "SdInfo.h"
|
||||
//------------------------------------------------------------------------------
|
||||
// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
|
||||
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_FULL_SPEED = 0;
|
||||
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_HALF_SPEED = 1;
|
||||
/** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_QUARTER_SPEED = 2;
|
||||
/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_EIGHTH_SPEED = 3;
|
||||
/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_SIXTEENTH_SPEED = 4;
|
||||
//------------------------------------------------------------------------------
|
||||
/** init timeout ms */
|
||||
uint16_t const SD_INIT_TIMEOUT = 2000;
|
||||
/** erase timeout ms */
|
||||
uint16_t const SD_ERASE_TIMEOUT = 10000;
|
||||
/** read timeout ms */
|
||||
uint16_t const SD_READ_TIMEOUT = 300;
|
||||
/** write time out ms */
|
||||
uint16_t const SD_WRITE_TIMEOUT = 600;
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card errors
|
||||
/** timeout error for command CMD0 (initialize card in SPI mode) */
|
||||
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
|
||||
/** CMD8 was not accepted - not a valid SD card*/
|
||||
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
|
||||
/** card returned an error response for CMD12 (write stop) */
|
||||
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
|
||||
/** card returned an error response for CMD17 (read block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
|
||||
/** card returned an error response for CMD18 (read multiple block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
|
||||
/** card returned an error response for CMD24 (write block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
|
||||
/** WRITE_MULTIPLE_BLOCKS command failed */
|
||||
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
|
||||
/** card returned an error response for CMD58 (read OCR) */
|
||||
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
|
||||
/** SET_WR_BLK_ERASE_COUNT failed */
|
||||
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
|
||||
/** ACMD41 initialization process timeout */
|
||||
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
|
||||
/** card returned a bad CSR version field */
|
||||
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
|
||||
/** erase block group command failed */
|
||||
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
|
||||
/** card not capable of single block erase */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
|
||||
/** Erase sequence timed out */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
|
||||
/** card returned an error token instead of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ = 0XF;
|
||||
/** read CID or CSD failed */
|
||||
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
|
||||
/** timeout while waiting for start of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
|
||||
/** card did not accept STOP_TRAN_TOKEN */
|
||||
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
|
||||
/** card returned an error token as a response to a write operation */
|
||||
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
|
||||
/** attempt to write protected block zero */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
|
||||
/** card did not go ready for a multiple block write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
|
||||
/** card returned an error to a CMD13 status check after a write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
|
||||
/** timeout occurred during write programming */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
|
||||
/** incorrect rate selected */
|
||||
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
|
||||
/** init() not called */
|
||||
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
|
||||
//------------------------------------------------------------------------------
|
||||
// card types
|
||||
/** Standard capacity V1 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD1 = 1;
|
||||
/** Standard capacity V2 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD2 = 2;
|
||||
/** High Capacity SD card */
|
||||
uint8_t const SD_CARD_TYPE_SDHC = 3;
|
||||
/**
|
||||
* define SOFTWARE_SPI to use bit-bang SPI
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
|
||||
#define SOFTWARE_SPI
|
||||
#elif USE_SOFTWARE_SPI
|
||||
#define SOFTWARE_SPI
|
||||
#endif // MEGA_SOFT_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
// SPI pin definitions - do not edit here - change in SdFatConfig.h
|
||||
//
|
||||
#ifndef SOFTWARE_SPI
|
||||
// hardware pin defs
|
||||
/** The default chip select pin for the SD card is SS. */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
|
||||
// The following three pins must not be redefined for hardware SPI.
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = MOSI_PIN;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = MISO_PIN;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = SCK_PIN;
|
||||
|
||||
#else // SOFTWARE_SPI
|
||||
|
||||
/** SPI chip select pin */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN;
|
||||
#endif // SOFTWARE_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class Sd2Card
|
||||
* \brief Raw access to SD and SDHC flash memory cards.
|
||||
*/
|
||||
class Sd2Card {
|
||||
public:
|
||||
/** Construct an instance of Sd2Card. */
|
||||
Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
|
||||
uint32_t cardSize();
|
||||
bool erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||
bool eraseSingleBlockEnable();
|
||||
/**
|
||||
* Set SD error code.
|
||||
* \param[in] code value for error code.
|
||||
*/
|
||||
void error(uint8_t code) {errorCode_ = code;}
|
||||
/**
|
||||
* \return error code for last error. See Sd2Card.h for a list of error codes.
|
||||
*/
|
||||
int errorCode() const {return errorCode_;}
|
||||
/** \return error data for last error. */
|
||||
int errorData() const {return status_;}
|
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip
|
||||
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool init(uint8_t sckRateID = SPI_FULL_SPEED,
|
||||
uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
|
||||
bool readBlock(uint32_t block, uint8_t* dst);
|
||||
/**
|
||||
* Read a card's CID register. The CID contains card identification
|
||||
* information such as Manufacturer ID, Product name, Product serial
|
||||
* number and Manufacturing date.
|
||||
*
|
||||
* \param[out] cid pointer to area for returned data.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readCID(cid_t* cid) {
|
||||
return readRegister(CMD10, cid);
|
||||
}
|
||||
/**
|
||||
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents.
|
||||
*
|
||||
* \param[out] csd pointer to area for returned data.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readCSD(csd_t* csd) {
|
||||
return readRegister(CMD9, csd);
|
||||
}
|
||||
bool readData(uint8_t *dst);
|
||||
bool readStart(uint32_t blockNumber);
|
||||
bool readStop();
|
||||
bool setSckRate(uint8_t sckRateID);
|
||||
/** Return the card type: SD V1, SD V2 or SDHC
|
||||
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
|
||||
*/
|
||||
int type() const {return type_;}
|
||||
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
|
||||
bool writeData(const uint8_t* src);
|
||||
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||
bool writeStop();
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t chipSelectPin_;
|
||||
uint8_t errorCode_;
|
||||
uint8_t spiRate_;
|
||||
uint8_t status_;
|
||||
uint8_t type_;
|
||||
// private functions
|
||||
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||
cardCommand(CMD55, 0);
|
||||
return cardCommand(cmd, arg);
|
||||
}
|
||||
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||
|
||||
bool readData(uint8_t* dst, uint16_t count);
|
||||
bool readRegister(uint8_t cmd, void* buf);
|
||||
void chipSelectHigh();
|
||||
void chipSelectLow();
|
||||
void type(uint8_t value) {type_ = value;}
|
||||
bool waitNotBusy(uint16_t timeoutMillis);
|
||||
bool writeData(uint8_t token, const uint8_t* src);
|
||||
};
|
||||
#endif // Sd2Card_h
|
||||
|
||||
|
||||
#endif
|
||||
+368
-353
@@ -1,353 +1,368 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2010 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Warning this file was generated by a program.
|
||||
#ifndef Sd2PinMap_h
|
||||
#define Sd2PinMap_h
|
||||
#include <avr/io.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/** struct for mapping digital pins */
|
||||
struct pin_map_t {
|
||||
volatile uint8_t* ddr;
|
||||
volatile uint8_t* pin;
|
||||
volatile uint8_t* port;
|
||||
uint8_t bit;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Mega
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 20;
|
||||
uint8_t const SCL_PIN = 21;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 53;
|
||||
uint8_t const MOSI_PIN = 51;
|
||||
uint8_t const MISO_PIN = 50;
|
||||
uint8_t const SCK_PIN = 52;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
// Sanguino
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 17;
|
||||
uint8_t const SCL_PIN = 18;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 4;
|
||||
uint8_t const MOSI_PIN = 5;
|
||||
uint8_t const MISO_PIN = 6;
|
||||
uint8_t const SCK_PIN = 7;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
// Teensy 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 6;
|
||||
uint8_t const SCL_PIN = 5;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 0;
|
||||
uint8_t const MOSI_PIN = 2;
|
||||
uint8_t const MISO_PIN = 3;
|
||||
uint8_t const SCK_PIN = 1;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 4
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 5
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 6
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 7
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 8
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 9
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 10
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 11
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 12
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 13
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 14
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 15
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 16
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 17
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 18
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 19
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 20
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 21
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 22
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 23
|
||||
{&DDRE, &PINE, &PORTE, 6} // E6 24
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
// Teensy++ 1.0 & 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 1;
|
||||
uint8_t const SCL_PIN = 0;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 20;
|
||||
uint8_t const MOSI_PIN = 22;
|
||||
uint8_t const MISO_PIN = 23;
|
||||
uint8_t const SCK_PIN = 21;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// 168 and 328 Arduinos
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 18;
|
||||
uint8_t const SCL_PIN = 19;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 10;
|
||||
uint8_t const MOSI_PIN = 11;
|
||||
uint8_t const MISO_PIN = 12;
|
||||
uint8_t const SCK_PIN = 13;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||
};
|
||||
#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
//------------------------------------------------------------------------------
|
||||
static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
|
||||
|
||||
uint8_t badPinNumber(void)
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
uint8_t getPinMode(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void setPinMode(uint8_t pin, uint8_t mode) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (mode) {
|
||||
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
uint8_t fastDigitalRead(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, uint8_t value) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (value) {
|
||||
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
#endif // Sd2PinMap_h
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2010 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Warning this file was generated by a program.
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef Sd2PinMap_h
|
||||
#define Sd2PinMap_h
|
||||
#include <avr/io.h>
|
||||
//------------------------------------------------------------------------------
|
||||
/** struct for mapping digital pins */
|
||||
struct pin_map_t {
|
||||
volatile uint8_t* ddr;
|
||||
volatile uint8_t* pin;
|
||||
volatile uint8_t* port;
|
||||
uint8_t bit;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__AVR_ATmega1280__)\
|
||||
|| defined(__AVR_ATmega2560__)
|
||||
// Mega
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 20; // D1
|
||||
uint8_t const SCL_PIN = 21; // D0
|
||||
|
||||
#undef MOSI_PIN
|
||||
#undef MISO_PIN
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 53; // B0
|
||||
uint8_t const MOSI_PIN = 51; // B2
|
||||
uint8_t const MISO_PIN = 50; // B3
|
||||
uint8_t const SCK_PIN = 52; // B1
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega644P__)\
|
||||
|| defined(__AVR_ATmega644__)\
|
||||
|| defined(__AVR_ATmega1284P__)
|
||||
// Sanguino
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 17; // C1
|
||||
uint8_t const SCL_PIN = 18; // C2
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 4; // B4
|
||||
uint8_t const MOSI_PIN = 5; // B5
|
||||
uint8_t const MISO_PIN = 6; // B6
|
||||
uint8_t const SCK_PIN = 7; // B7
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
// Teensy 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 6; // D1
|
||||
uint8_t const SCL_PIN = 5; // D0
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 0; // B0
|
||||
uint8_t const MOSI_PIN = 2; // B2
|
||||
uint8_t const MISO_PIN = 3; // B3
|
||||
uint8_t const SCK_PIN = 1; // B1
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 4
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 5
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 6
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 7
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 8
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 9
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 10
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 11
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 12
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 13
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 14
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 15
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 16
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 17
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 18
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 19
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 20
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 21
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 22
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 23
|
||||
{&DDRE, &PINE, &PORTE, 6} // E6 24
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_AT90USB646__)\
|
||||
|| defined(__AVR_AT90USB1286__)
|
||||
// Teensy++ 1.0 & 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 1; // D1
|
||||
uint8_t const SCL_PIN = 0; // D0
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 20; // B0
|
||||
uint8_t const MOSI_PIN = 22; // B2
|
||||
uint8_t const MISO_PIN = 23; // B3
|
||||
uint8_t const SCK_PIN = 21; // B1
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega168__)\
|
||||
||defined(__AVR_ATmega168P__)\
|
||||
||defined(__AVR_ATmega328P__)
|
||||
// 168 and 328 Arduinos
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 18; // C4
|
||||
uint8_t const SCL_PIN = 19; // C5
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 10; // B2
|
||||
uint8_t const MOSI_PIN = 11; // B3
|
||||
uint8_t const MISO_PIN = 12; // B4
|
||||
uint8_t const SCK_PIN = 13; // B5
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||
};
|
||||
#else // defined(__AVR_ATmega1280__)
|
||||
#error unknown chip
|
||||
#endif // defined(__AVR_ATmega1280__)
|
||||
//------------------------------------------------------------------------------
|
||||
static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
|
||||
|
||||
uint8_t badPinNumber(void)
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
bool getPinMode(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void setPinMode(uint8_t pin, uint8_t mode) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (mode) {
|
||||
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
bool fastDigitalRead(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, uint8_t value) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (value) {
|
||||
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
#endif // Sd2PinMap_h
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,483 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef SdBaseFile_h
|
||||
#define SdBaseFile_h
|
||||
/**
|
||||
* \file
|
||||
* \brief SdBaseFile class
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#include "SdFatConfig.h"
|
||||
#include "SdVolume.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct fpos_t
|
||||
* \brief internal type for istream
|
||||
* do not use in user apps
|
||||
*/
|
||||
struct fpos_t {
|
||||
/** stream position */
|
||||
uint32_t position;
|
||||
/** cluster for position */
|
||||
uint32_t cluster;
|
||||
fpos_t() : position(0), cluster(0) {}
|
||||
};
|
||||
|
||||
// use the gnu style oflag in open()
|
||||
/** open() oflag for reading */
|
||||
uint8_t const O_READ = 0X01;
|
||||
/** open() oflag - same as O_IN */
|
||||
uint8_t const O_RDONLY = O_READ;
|
||||
/** open() oflag for write */
|
||||
uint8_t const O_WRITE = 0X02;
|
||||
/** open() oflag - same as O_WRITE */
|
||||
uint8_t const O_WRONLY = O_WRITE;
|
||||
/** open() oflag for reading and writing */
|
||||
uint8_t const O_RDWR = (O_READ | O_WRITE);
|
||||
/** open() oflag mask for access modes */
|
||||
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
|
||||
/** The file offset shall be set to the end of the file prior to each write. */
|
||||
uint8_t const O_APPEND = 0X04;
|
||||
/** synchronous writes - call sync() after each write */
|
||||
uint8_t const O_SYNC = 0X08;
|
||||
/** truncate the file to zero length */
|
||||
uint8_t const O_TRUNC = 0X10;
|
||||
/** set the initial position at the end of the file */
|
||||
uint8_t const O_AT_END = 0X20;
|
||||
/** create the file if nonexistent */
|
||||
uint8_t const O_CREAT = 0X40;
|
||||
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||
uint8_t const O_EXCL = 0X80;
|
||||
|
||||
// SdBaseFile class static and const definitions
|
||||
// flags for ls()
|
||||
/** ls() flag to print modify date */
|
||||
uint8_t const LS_DATE = 1;
|
||||
/** ls() flag to print file size */
|
||||
uint8_t const LS_SIZE = 2;
|
||||
/** ls() flag for recursive list of subdirectories */
|
||||
uint8_t const LS_R = 4;
|
||||
|
||||
|
||||
// flags for timestamp
|
||||
/** set the file's last access date */
|
||||
uint8_t const T_ACCESS = 1;
|
||||
/** set the file's creation date and time */
|
||||
uint8_t const T_CREATE = 2;
|
||||
/** Set the file's write date and time */
|
||||
uint8_t const T_WRITE = 4;
|
||||
// values for type_
|
||||
/** This file has not been opened. */
|
||||
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
|
||||
/** A normal file */
|
||||
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
|
||||
/** A FAT12 or FAT16 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT_FIXED = 2;
|
||||
/** A FAT32 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
|
||||
/** A subdirectory file*/
|
||||
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
|
||||
/** Test value for directory type */
|
||||
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED;
|
||||
|
||||
/** date field for FAT directory entry
|
||||
* \param[in] year [1980,2107]
|
||||
* \param[in] month [1,12]
|
||||
* \param[in] day [1,31]
|
||||
*
|
||||
* \return Packed date for dir_t entry.
|
||||
*/
|
||||
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
|
||||
return (year - 1980) << 9 | month << 5 | day;
|
||||
}
|
||||
/** year part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted year [1980,2107]
|
||||
*/
|
||||
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
|
||||
return 1980 + (fatDate >> 9);
|
||||
}
|
||||
/** month part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted month [1,12]
|
||||
*/
|
||||
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
|
||||
return (fatDate >> 5) & 0XF;
|
||||
}
|
||||
/** day part of FAT directory date field
|
||||
* \param[in] fatDate Date in packed dir format.
|
||||
*
|
||||
* \return Extracted day [1,31]
|
||||
*/
|
||||
static inline uint8_t FAT_DAY(uint16_t fatDate) {
|
||||
return fatDate & 0X1F;
|
||||
}
|
||||
/** time field for FAT directory entry
|
||||
* \param[in] hour [0,23]
|
||||
* \param[in] minute [0,59]
|
||||
* \param[in] second [0,59]
|
||||
*
|
||||
* \return Packed time for dir_t entry.
|
||||
*/
|
||||
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
return hour << 11 | minute << 5 | second >> 1;
|
||||
}
|
||||
/** hour part of FAT directory time field
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted hour [0,23]
|
||||
*/
|
||||
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
|
||||
return fatTime >> 11;
|
||||
}
|
||||
/** minute part of FAT directory time field
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted minute [0,59]
|
||||
*/
|
||||
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
|
||||
return(fatTime >> 5) & 0X3F;
|
||||
}
|
||||
/** second part of FAT directory time field
|
||||
* Note second/2 is stored in packed time.
|
||||
*
|
||||
* \param[in] fatTime Time in packed dir format.
|
||||
*
|
||||
* \return Extracted second [0,58]
|
||||
*/
|
||||
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
|
||||
return 2*(fatTime & 0X1F);
|
||||
}
|
||||
/** Default date for file timestamps is 1 Jan 2000 */
|
||||
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||
/** Default time for file timestamp is 1 am */
|
||||
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdBaseFile
|
||||
* \brief Base class for SdFile with Print and C++ streams.
|
||||
*/
|
||||
class SdBaseFile {
|
||||
public:
|
||||
/** Create an instance. */
|
||||
SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {}
|
||||
SdBaseFile(const char* path, uint8_t oflag);
|
||||
~SdBaseFile() {if(isOpen()) close();}
|
||||
/**
|
||||
* writeError is set to true if an error occurs during a write().
|
||||
* Set writeError to false before calling print() and/or write() and check
|
||||
* for true after calls to print() and/or write().
|
||||
*/
|
||||
bool writeError;
|
||||
//----------------------------------------------------------------------------
|
||||
// helpers for stream classes
|
||||
/** get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
*/
|
||||
void getpos(fpos_t* pos);
|
||||
/** set position for streams
|
||||
* \param[out] pos struct with value for new position
|
||||
*/
|
||||
void setpos(fpos_t* pos);
|
||||
//----------------------------------------------------------------------------
|
||||
bool close();
|
||||
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
bool createContiguous(SdBaseFile* dirFile,
|
||||
const char* path, uint32_t size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {return curCluster_;}
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition() const {return curPosition_;}
|
||||
/** \return Current working directory */
|
||||
static SdBaseFile* cwd() {return cwd_;}
|
||||
/** Set the date/time callback function
|
||||
*
|
||||
* \param[in] dateTime The user's call back function. The callback
|
||||
* function is of the form:
|
||||
*
|
||||
* \code
|
||||
* void dateTime(uint16_t* date, uint16_t* time) {
|
||||
* uint16_t year;
|
||||
* uint8_t month, day, hour, minute, second;
|
||||
*
|
||||
* // User gets date and time from GPS or real-time clock here
|
||||
*
|
||||
* // return date using FAT_DATE macro to format fields
|
||||
* *date = FAT_DATE(year, month, day);
|
||||
*
|
||||
* // return time using FAT_TIME macro to format fields
|
||||
* *time = FAT_TIME(hour, minute, second);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Sets the function that is called when a file is created or when
|
||||
* a file's directory entry is modified by sync(). All timestamps,
|
||||
* access, creation, and modify, are set when a file is created.
|
||||
* sync() maintains the last access date and last modify date/time.
|
||||
*
|
||||
* See the timestamp() function.
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||
dateTime_ = dateTime;
|
||||
}
|
||||
/** Cancel the date/time callback function. */
|
||||
static void dateTimeCallbackCancel() {dateTime_ = 0;}
|
||||
bool dirEntry(dir_t* dir);
|
||||
static void dirName(const dir_t& dir, char* name);
|
||||
bool exists(const char* name);
|
||||
int16_t fgets(char* str, int16_t num, char* delim = 0);
|
||||
/** \return The total number of bytes in a file or directory. */
|
||||
uint32_t fileSize() const {return fileSize_;}
|
||||
/** \return The first cluster number for a file or directory. */
|
||||
uint32_t firstCluster() const {return firstCluster_;}
|
||||
bool getFilename(char* name);
|
||||
/** \return True if this is a directory else false. */
|
||||
bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
|
||||
/** \return True if this is a normal file else false. */
|
||||
bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;}
|
||||
/** \return True if this is an open file/directory else false. */
|
||||
bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;}
|
||||
/** \return True if this is a subdirectory else false. */
|
||||
bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;}
|
||||
/** \return True if this is the root directory. */
|
||||
bool isRoot() const {
|
||||
return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32;
|
||||
}
|
||||
void ls( uint8_t flags = 0, uint8_t indent = 0);
|
||||
bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true);
|
||||
// alias for backward compactability
|
||||
bool makeDir(SdBaseFile* dir, const char* path) {
|
||||
return mkdir(dir, path, false);
|
||||
}
|
||||
bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
|
||||
bool open(const char* path, uint8_t oflag = O_READ);
|
||||
bool openNext(SdBaseFile* dirFile, uint8_t oflag);
|
||||
bool openRoot(SdVolume* vol);
|
||||
int peek();
|
||||
static void printFatDate(uint16_t fatDate);
|
||||
static void printFatTime( uint16_t fatTime);
|
||||
bool printName();
|
||||
int16_t read();
|
||||
int16_t read(void* buf, uint16_t nbyte);
|
||||
int8_t readDir(dir_t* dir);
|
||||
static bool remove(SdBaseFile* dirFile, const char* path);
|
||||
bool remove();
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {seekSet(0);}
|
||||
bool rename(SdBaseFile* dirFile, const char* newPath);
|
||||
bool rmdir();
|
||||
// for backward compatibility
|
||||
bool rmDir() {return rmdir();}
|
||||
bool rmRfStar();
|
||||
/** Set the files position to current position + \a pos. See seekSet().
|
||||
* \param[in] offset The new position in bytes from the current position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekCur(int32_t offset) {
|
||||
return seekSet(curPosition_ + offset);
|
||||
}
|
||||
/** Set the files position to end-of-file + \a offset. See seekSet().
|
||||
* \param[in] offset The new position in bytes from end-of-file.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekEnd(int32_t offset = 0) {return seekSet(fileSize_ + offset);}
|
||||
bool seekSet(uint32_t pos);
|
||||
bool sync();
|
||||
bool timestamp(SdBaseFile* file);
|
||||
bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t second);
|
||||
/** Type of file. You should use isFile() or isDir() instead of type()
|
||||
* if possible.
|
||||
*
|
||||
* \return The file or directory type.
|
||||
*/
|
||||
uint8_t type() const {return type_;}
|
||||
bool truncate(uint32_t size);
|
||||
/** \return SdVolume that contains this file. */
|
||||
SdVolume* volume() const {return vol_;}
|
||||
int16_t write(const void* buf, uint16_t nbyte);
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
// allow SdFat to set cwd_
|
||||
friend class SdFat;
|
||||
// global pointer to cwd dir
|
||||
static SdBaseFile* cwd_;
|
||||
// data time callback function
|
||||
static void (*dateTime_)(uint16_t* date, uint16_t* time);
|
||||
// bits defined in flags_
|
||||
// should be 0X0F
|
||||
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
|
||||
// sync of directory entry required
|
||||
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
|
||||
|
||||
// private data
|
||||
uint8_t flags_; // See above for definition of flags_ bits
|
||||
uint8_t fstate_; // error and eof indicator
|
||||
uint8_t type_; // type of file see above for values
|
||||
uint32_t curCluster_; // cluster for current file position
|
||||
uint32_t curPosition_; // current file position in bytes from beginning
|
||||
uint32_t dirBlock_; // block for this files directory entry
|
||||
uint8_t dirIndex_; // index of directory entry in dirBlock
|
||||
uint32_t fileSize_; // file size in bytes
|
||||
uint32_t firstCluster_; // first cluster of file
|
||||
SdVolume* vol_; // volume where file is located
|
||||
|
||||
/** experimental don't use */
|
||||
bool openParent(SdBaseFile* dir);
|
||||
// private functions
|
||||
bool addCluster();
|
||||
bool addDirCluster();
|
||||
dir_t* cacheDirEntry(uint8_t action);
|
||||
int8_t lsPrintNext( uint8_t flags, uint8_t indent);
|
||||
static bool make83Name(const char* str, uint8_t* name, const char** ptr);
|
||||
bool mkdir(SdBaseFile* parent, const uint8_t dname[11]);
|
||||
bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag);
|
||||
bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||
dir_t* readDirCache();
|
||||
//------------------------------------------------------------------------------
|
||||
// to be deleted
|
||||
static void printDirName( const dir_t& dir,
|
||||
uint8_t width, bool printSlash);
|
||||
//------------------------------------------------------------------------------
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
|
||||
public:
|
||||
/** \deprecated Use:
|
||||
* bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
* \param[out] bgnBlock the first block address for the file.
|
||||
* \param[out] endBlock the last block address for the file.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
|
||||
return contiguousRange(&bgnBlock, &endBlock);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* bool createContiguous(SdBaseFile* dirFile,
|
||||
* const char* path, uint32_t size)
|
||||
* \param[in] dirFile The directory where the file will be created.
|
||||
* \param[in] path A path with a valid DOS 8.3 file name.
|
||||
* \param[in] size The desired file size.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(SdBaseFile& dirFile, // NOLINT
|
||||
const char* path, uint32_t size) {
|
||||
return createContiguous(&dirFile, path, size);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* static void dateTimeCallback(
|
||||
* void (*dateTime)(uint16_t* date, uint16_t* time));
|
||||
* \param[in] dateTime The user's call back function.
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
|
||||
oldDateTime_ = dateTime;
|
||||
dateTime_ = dateTime ? oldToNew : 0;
|
||||
}
|
||||
/** \deprecated Use: bool dirEntry(dir_t* dir);
|
||||
* \param[out] dir Location for return of the file's directory entry.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* bool mkdir(SdBaseFile* dir, const char* path);
|
||||
* \param[in] dir An open SdFat instance for the directory that will contain
|
||||
* the new directory.
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the new directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT
|
||||
return mkdir(&dir, path);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
|
||||
* \param[in] dirFile An open SdFat instance for the directory containing the
|
||||
* file to be opened.
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(SdBaseFile& dirFile, // NOLINT
|
||||
const char* path, uint8_t oflag) {
|
||||
return open(&dirFile, path, oflag);
|
||||
}
|
||||
/** \deprecated Do not use in new apps
|
||||
* \param[in] dirFile An open SdFat instance for the directory containing the
|
||||
* file to be opened.
|
||||
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(SdBaseFile& dirFile, const char* path) { // NOLINT
|
||||
return open(dirFile, path, O_RDWR);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
* \param[in] dirFile An open SdFat instance for the directory.
|
||||
* \param[in] index The \a index of the directory entry for the file to be
|
||||
* opened. The value for \a index is (directory file position)/32.
|
||||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
|
||||
return open(&dirFile, index, oflag);
|
||||
}
|
||||
/** \deprecated Use: bool openRoot(SdVolume* vol);
|
||||
* \param[in] vol The FAT volume containing the root directory to be opened.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
|
||||
/** \deprecated Use: int8_t readDir(dir_t* dir);
|
||||
* \param[out] dir The dir_t struct that will receive the data.
|
||||
* \return bytes read for success zero for eof or -1 for failure.
|
||||
*/
|
||||
int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* static uint8_t remove(SdBaseFile* dirFile, const char* path);
|
||||
* \param[in] dirFile The directory that contains the file.
|
||||
* \param[in] path The name of the file to be removed.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT
|
||||
return remove(&dirFile, path);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// rest are private
|
||||
private:
|
||||
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
|
||||
static void oldToNew(uint16_t* date, uint16_t* time) {
|
||||
uint16_t d;
|
||||
uint16_t t;
|
||||
oldDateTime_(d, t);
|
||||
*date = d;
|
||||
*time = t;
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
};
|
||||
|
||||
#endif // SdBaseFile_h
|
||||
#endif
|
||||
-547
@@ -1,547 +0,0 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdFat_h
|
||||
#define SdFat_h
|
||||
/**
|
||||
* \file
|
||||
* SdFile and SdVolume classes
|
||||
*/
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Sd2Card.h"
|
||||
#include "FatStructs.h"
|
||||
#include "Print.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Allow use of deprecated functions if non-zero
|
||||
*/
|
||||
#define ALLOW_DEPRECATED_FUNCTIONS 1
|
||||
//------------------------------------------------------------------------------
|
||||
// forward declaration since SdVolume is used in SdFile
|
||||
class SdVolume;
|
||||
//==============================================================================
|
||||
// SdFile class
|
||||
|
||||
// flags for ls()
|
||||
/** ls() flag to print modify date */
|
||||
uint8_t const LS_DATE = 1;
|
||||
/** ls() flag to print file size */
|
||||
uint8_t const LS_SIZE = 2;
|
||||
/** ls() flag for recursive list of subdirectories */
|
||||
uint8_t const LS_R = 4;
|
||||
|
||||
// use the gnu style oflag in open()
|
||||
/** open() oflag for reading */
|
||||
uint8_t const O_READ = 0X01;
|
||||
/** open() oflag - same as O_READ */
|
||||
uint8_t const O_RDONLY = O_READ;
|
||||
/** open() oflag for write */
|
||||
uint8_t const O_WRITE = 0X02;
|
||||
/** open() oflag - same as O_WRITE */
|
||||
uint8_t const O_WRONLY = O_WRITE;
|
||||
/** open() oflag for reading and writing */
|
||||
uint8_t const O_RDWR = (O_READ | O_WRITE);
|
||||
/** open() oflag mask for access modes */
|
||||
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
|
||||
/** The file offset shall be set to the end of the file prior to each write. */
|
||||
uint8_t const O_APPEND = 0X04;
|
||||
/** synchronous writes - call sync() after each write */
|
||||
uint8_t const O_SYNC = 0X08;
|
||||
/** create the file if nonexistent */
|
||||
uint8_t const O_CREAT = 0X10;
|
||||
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||
uint8_t const O_EXCL = 0X20;
|
||||
/** truncate the file to zero length */
|
||||
uint8_t const O_TRUNC = 0X40;
|
||||
|
||||
// flags for timestamp
|
||||
/** set the file's last access date */
|
||||
uint8_t const T_ACCESS = 1;
|
||||
/** set the file's creation date and time */
|
||||
uint8_t const T_CREATE = 2;
|
||||
/** Set the file's write date and time */
|
||||
uint8_t const T_WRITE = 4;
|
||||
// values for type_
|
||||
/** This SdFile has not been opened. */
|
||||
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
|
||||
/** SdFile for a file */
|
||||
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
|
||||
/** SdFile for a FAT16 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
|
||||
/** SdFile for a FAT32 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
|
||||
/** SdFile for a subdirectory */
|
||||
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
|
||||
/** Test value for directory type */
|
||||
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
|
||||
|
||||
/** date field for FAT directory entry */
|
||||
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
|
||||
return (year - 1980) << 9 | month << 5 | day;
|
||||
}
|
||||
/** year part of FAT directory date field */
|
||||
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
|
||||
return 1980 + (fatDate >> 9);
|
||||
}
|
||||
/** month part of FAT directory date field */
|
||||
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
|
||||
return (fatDate >> 5) & 0XF;
|
||||
}
|
||||
/** day part of FAT directory date field */
|
||||
static inline uint8_t FAT_DAY(uint16_t fatDate) {
|
||||
return fatDate & 0X1F;
|
||||
}
|
||||
/** time field for FAT directory entry */
|
||||
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
return hour << 11 | minute << 5 | second >> 1;
|
||||
}
|
||||
/** hour part of FAT directory time field */
|
||||
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
|
||||
return fatTime >> 11;
|
||||
}
|
||||
/** minute part of FAT directory time field */
|
||||
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
|
||||
return(fatTime >> 5) & 0X3F;
|
||||
}
|
||||
/** second part of FAT directory time field */
|
||||
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
|
||||
return 2*(fatTime & 0X1F);
|
||||
}
|
||||
/** Default date for file timestamps is 1 Jan 2000 */
|
||||
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||
/** Default time for file timestamp is 1 am */
|
||||
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdFile
|
||||
* \brief Access FAT16 and FAT32 files on SD and SDHC cards.
|
||||
*/
|
||||
class SdFile : public Print {
|
||||
public:
|
||||
/** Create an instance of SdFile. */
|
||||
SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
|
||||
/**
|
||||
* writeError is set to true if an error occurs during a write().
|
||||
* Set writeError to false before calling print() and/or write() and check
|
||||
* for true after calls to print() and/or write().
|
||||
*/
|
||||
bool writeError;
|
||||
/**
|
||||
* Cancel unbuffered reads for this file.
|
||||
* See setUnbufferedRead()
|
||||
*/
|
||||
void clearUnbufferedRead(void) {
|
||||
flags_ &= ~F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
uint8_t close(void);
|
||||
uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
uint8_t createContiguous(SdFile* dirFile,
|
||||
const char* fileName, uint32_t size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster(void) const {return curCluster_;}
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition(void) const {return curPosition_;}
|
||||
/**
|
||||
* Set the date/time callback function
|
||||
*
|
||||
* \param[in] dateTime The user's call back function. The callback
|
||||
* function is of the form:
|
||||
*
|
||||
* \code
|
||||
* void dateTime(uint16_t* date, uint16_t* time) {
|
||||
* uint16_t year;
|
||||
* uint8_t month, day, hour, minute, second;
|
||||
*
|
||||
* // User gets date and time from GPS or real-time clock here
|
||||
*
|
||||
* // return date using FAT_DATE macro to format fields
|
||||
* *date = FAT_DATE(year, month, day);
|
||||
*
|
||||
* // return time using FAT_TIME macro to format fields
|
||||
* *time = FAT_TIME(hour, minute, second);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Sets the function that is called when a file is created or when
|
||||
* a file's directory entry is modified by sync(). All timestamps,
|
||||
* access, creation, and modify, are set when a file is created.
|
||||
* sync() maintains the last access date and last modify date/time.
|
||||
*
|
||||
* See the timestamp() function.
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||
dateTime_ = dateTime;
|
||||
}
|
||||
/**
|
||||
* Cancel the date/time callback function.
|
||||
*/
|
||||
static void dateTimeCallbackCancel(void) {
|
||||
// use explicit zero since NULL is not defined for Sanguino
|
||||
dateTime_ = 0;
|
||||
}
|
||||
/** \return Address of the block that contains this file's directory. */
|
||||
uint32_t dirBlock(void) const {return dirBlock_;}
|
||||
uint8_t dirEntry(dir_t* dir);
|
||||
/** \return Index of this file's directory in the block dirBlock. */
|
||||
uint8_t dirIndex(void) const {return dirIndex_;}
|
||||
static void dirName(const dir_t& dir, char* name);
|
||||
/** \return The total number of bytes in a file or directory. */
|
||||
uint32_t fileSize(void) const {return fileSize_;}
|
||||
/** \return The first cluster number for a file or directory. */
|
||||
uint32_t firstCluster(void) const {return firstCluster_;}
|
||||
/** \return True if this is a SdFile for a directory else false. */
|
||||
uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
|
||||
/** \return True if this is a SdFile for a file else false. */
|
||||
uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
|
||||
/** \return True if this is a SdFile for an open file/directory else false. */
|
||||
uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
|
||||
/** \return True if this is a SdFile for a subdirectory else false. */
|
||||
uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
|
||||
/** \return True if this is a SdFile for the root directory. */
|
||||
uint8_t isRoot(void) const {
|
||||
return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
|
||||
}
|
||||
void ls(uint8_t flags = 0, uint8_t indent = 0);
|
||||
uint8_t makeDir(SdFile* dir, const char* dirName);
|
||||
uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||
|
||||
uint8_t openRoot(SdVolume* vol);
|
||||
static void printDirName(const dir_t& dir, uint8_t width);
|
||||
static void printFatDate(uint16_t fatDate);
|
||||
static void printFatTime(uint16_t fatTime);
|
||||
static void printTwoDigits(uint8_t v);
|
||||
/**
|
||||
* Read the next byte from a file.
|
||||
*
|
||||
* \return For success read returns the next byte in the file as an int.
|
||||
* If an error occurs or end of file is reached -1 is returned.
|
||||
*/
|
||||
int16_t read(void) {
|
||||
uint8_t b;
|
||||
return read(&b, 1) == 1 ? b : -1;
|
||||
}
|
||||
int16_t read(void* buf, uint16_t nbyte);
|
||||
int8_t readDir(dir_t* dir);
|
||||
static uint8_t remove(SdFile* dirFile, const char* fileName);
|
||||
uint8_t remove(void);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind(void) {
|
||||
curPosition_ = curCluster_ = 0;
|
||||
}
|
||||
uint8_t rmDir(void);
|
||||
uint8_t rmRfStar(void);
|
||||
/** Set the files position to current position + \a pos. See seekSet(). */
|
||||
uint8_t seekCur(uint32_t pos) {
|
||||
return seekSet(curPosition_ + pos);
|
||||
}
|
||||
/**
|
||||
* Set the files current position to end of file. Useful to position
|
||||
* a file for append. See seekSet().
|
||||
*/
|
||||
uint8_t seekEnd(void) {return seekSet(fileSize_);}
|
||||
uint8_t seekSet(uint32_t pos);
|
||||
/**
|
||||
* Use unbuffered reads to access this file. Used with Wave
|
||||
* Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
|
||||
*
|
||||
* Not recommended for normal applications.
|
||||
*/
|
||||
void setUnbufferedRead(void) {
|
||||
if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t second);
|
||||
uint8_t sync(void);
|
||||
/** Type of this SdFile. You should use isFile() or isDir() instead of type()
|
||||
* if possible.
|
||||
*
|
||||
* \return The file or directory type.
|
||||
*/
|
||||
uint8_t type(void) const {return type_;}
|
||||
uint8_t truncate(uint32_t size);
|
||||
/** \return Unbuffered read flag. */
|
||||
uint8_t unbufferedRead(void) const {
|
||||
return flags_ & F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
/** \return SdVolume that contains this file. */
|
||||
SdVolume* volume(void) const {return vol_;}
|
||||
void write(uint8_t b);
|
||||
int16_t write(const void* buf, uint16_t nbyte);
|
||||
void write(const char* str);
|
||||
void write_P(PGM_P str);
|
||||
void writeln_P(PGM_P str);
|
||||
//------------------------------------------------------------------------------
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
*/
|
||||
uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
|
||||
return contiguousRange(&bgnBlock, &endBlock);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::createContiguous(SdFile* dirFile,
|
||||
* const char* fileName, uint32_t size)
|
||||
*/
|
||||
uint8_t createContiguous(SdFile& dirFile, // NOLINT
|
||||
const char* fileName, uint32_t size) {
|
||||
return createContiguous(&dirFile, fileName, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \deprecated Use:
|
||||
* static void SdFile::dateTimeCallback(
|
||||
* void (*dateTime)(uint16_t* date, uint16_t* time));
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
|
||||
oldDateTime_ = dateTime;
|
||||
dateTime_ = dateTime ? oldToNew : 0;
|
||||
}
|
||||
/** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
|
||||
uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
|
||||
*/
|
||||
uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
|
||||
return makeDir(&dir, dirName);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||
*/
|
||||
uint8_t open(SdFile& dirFile, // NOLINT
|
||||
const char* fileName, uint8_t oflag) {
|
||||
return open(&dirFile, fileName, oflag);
|
||||
}
|
||||
/** \deprecated Do not use in new apps */
|
||||
uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||
return open(dirFile, fileName, O_RDWR);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
*/
|
||||
uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
|
||||
return open(&dirFile, index, oflag);
|
||||
}
|
||||
/** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
|
||||
uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
|
||||
|
||||
/** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
|
||||
int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
|
||||
*/
|
||||
static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||
return remove(&dirFile, fileName);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// rest are private
|
||||
private:
|
||||
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
|
||||
static void oldToNew(uint16_t* date, uint16_t* time) {
|
||||
uint16_t d;
|
||||
uint16_t t;
|
||||
oldDateTime_(d, t);
|
||||
*date = d;
|
||||
*time = t;
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
private:
|
||||
// bits defined in flags_
|
||||
// should be 0XF
|
||||
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
|
||||
// available bits
|
||||
static uint8_t const F_UNUSED = 0X30;
|
||||
// use unbuffered SD read
|
||||
static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
|
||||
// sync of directory entry required
|
||||
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
|
||||
|
||||
// make sure F_OFLAG is ok
|
||||
#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
|
||||
#error flags_ bits conflict
|
||||
#endif // flags_ bits
|
||||
|
||||
// private data
|
||||
uint8_t flags_; // See above for definition of flags_ bits
|
||||
uint8_t type_; // type of file see above for values
|
||||
uint32_t curCluster_; // cluster for current file position
|
||||
uint32_t curPosition_; // current file position in bytes from beginning
|
||||
uint32_t dirBlock_; // SD block that contains directory entry for file
|
||||
uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
|
||||
uint32_t fileSize_; // file size in bytes
|
||||
uint32_t firstCluster_; // first cluster of file
|
||||
SdVolume* vol_; // volume where file is located
|
||||
|
||||
// private functions
|
||||
uint8_t addCluster(void);
|
||||
uint8_t addDirCluster(void);
|
||||
dir_t* cacheDirEntry(uint8_t action);
|
||||
static void (*dateTime_)(uint16_t* date, uint16_t* time);
|
||||
static uint8_t make83Name(const char* str, uint8_t* name);
|
||||
uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||
dir_t* readDirCache(void);
|
||||
};
|
||||
//==============================================================================
|
||||
// SdVolume class
|
||||
/**
|
||||
* \brief Cache for an SD data block
|
||||
*/
|
||||
union cache_t {
|
||||
/** Used to access cached file data blocks. */
|
||||
uint8_t data[512];
|
||||
/** Used to access cached FAT16 entries. */
|
||||
uint16_t fat16[256];
|
||||
/** Used to access cached FAT32 entries. */
|
||||
uint32_t fat32[128];
|
||||
/** Used to access cached directory entries. */
|
||||
dir_t dir[16];
|
||||
/** Used to access a cached MasterBoot Record. */
|
||||
mbr_t mbr;
|
||||
/** Used to access to a cached FAT boot sector. */
|
||||
fbs_t fbs;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdVolume
|
||||
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||
*/
|
||||
class SdVolume {
|
||||
public:
|
||||
/** Create an instance of SdVolume */
|
||||
SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
|
||||
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||
* recorder to do raw write to the SD card. Not for normal apps.
|
||||
*/
|
||||
static uint8_t* cacheClear(void) {
|
||||
cacheFlush();
|
||||
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||
return cacheBuffer_.data;
|
||||
}
|
||||
/**
|
||||
* Initialize a FAT volume. Try partition one first then try super
|
||||
* floppy format.
|
||||
*
|
||||
* \param[in] dev The Sd2Card where the volume is located.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. Reasons for
|
||||
* failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system or an I/O error.
|
||||
*/
|
||||
uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
|
||||
uint8_t init(Sd2Card* dev, uint8_t part);
|
||||
|
||||
// inline functions that return volume info
|
||||
/** \return The volume's cluster size in blocks. */
|
||||
uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
|
||||
/** \return The number of blocks in one FAT. */
|
||||
uint32_t blocksPerFat(void) const {return blocksPerFat_;}
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount(void) const {return clusterCount_;}
|
||||
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||
uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
|
||||
/** \return The logical block number for the start of file data. */
|
||||
uint32_t dataStartBlock(void) const {return dataStartBlock_;}
|
||||
/** \return The number of FAT structures on the volume. */
|
||||
uint8_t fatCount(void) const {return fatCount_;}
|
||||
/** \return The logical block number for the start of the first FAT. */
|
||||
uint32_t fatStartBlock(void) const {return fatStartBlock_;}
|
||||
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||
uint8_t fatType(void) const {return fatType_;}
|
||||
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||
uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
|
||||
/** \return The logical block number for the start of the root directory
|
||||
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||
uint32_t rootDirStart(void) const {return rootDirStart_;}
|
||||
/** return a pointer to the Sd2Card object for this volume */
|
||||
static Sd2Card* sdCard(void) {return sdCard_;}
|
||||
//------------------------------------------------------------------------------
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
|
||||
uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
|
||||
|
||||
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
|
||||
uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
|
||||
return init(&dev, part);
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
// Allow SdFile access to SdVolume private data.
|
||||
friend class SdFile;
|
||||
|
||||
// value for action argument in cacheRawBlock to indicate read from cache
|
||||
static uint8_t const CACHE_FOR_READ = 0;
|
||||
// value for action argument in cacheRawBlock to indicate cache dirty
|
||||
static uint8_t const CACHE_FOR_WRITE = 1;
|
||||
|
||||
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
static Sd2Card* sdCard_; // Sd2Card object for cache
|
||||
static uint8_t cacheDirty_; // cacheFlush() will write block if true
|
||||
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
//
|
||||
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||
uint32_t blocksPerFat_; // FAT size in blocks
|
||||
uint32_t clusterCount_; // clusters in one FAT
|
||||
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||
uint32_t dataStartBlock_; // first data block number
|
||||
uint8_t fatCount_; // number of FATs on volume
|
||||
uint32_t fatStartBlock_; // start block for first FAT
|
||||
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
|
||||
uint8_t blockOfCluster(uint32_t position) const {
|
||||
return (position >> 9) & (blocksPerCluster_ - 1);}
|
||||
uint32_t clusterStartBlock(uint32_t cluster) const {
|
||||
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
|
||||
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
|
||||
return clusterStartBlock(cluster) + blockOfCluster(position);}
|
||||
static uint8_t cacheFlush(void);
|
||||
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
|
||||
static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||
static uint8_t cacheZeroBlock(uint32_t blockNumber);
|
||||
uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
|
||||
uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
|
||||
uint8_t fatPut(uint32_t cluster, uint32_t value);
|
||||
uint8_t fatPutEOC(uint32_t cluster) {
|
||||
return fatPut(cluster, 0x0FFFFFFF);
|
||||
}
|
||||
uint8_t freeChain(uint32_t cluster);
|
||||
uint8_t isEOC(uint32_t cluster) const {
|
||||
return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
|
||||
}
|
||||
uint8_t readBlock(uint32_t block, uint8_t* dst) {
|
||||
return sdCard_->readBlock(block, dst);}
|
||||
uint8_t readData(uint32_t block, uint16_t offset,
|
||||
uint16_t count, uint8_t* dst) {
|
||||
return sdCard_->readData(block, offset, count, dst);
|
||||
}
|
||||
uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
|
||||
return sdCard_->writeBlock(block, dst);
|
||||
}
|
||||
};
|
||||
#endif // SdFat_h
|
||||
@@ -0,0 +1,114 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief configuration definitions
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef SdFatConfig_h
|
||||
#define SdFatConfig_h
|
||||
#include <stdint.h>
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
|
||||
*
|
||||
* Using multiple cards costs 400 - 500 bytes of flash.
|
||||
*
|
||||
* Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
|
||||
*/
|
||||
#define USE_MULTIPLE_CARDS 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
|
||||
*
|
||||
* The standard for iostreams is to call flush. This is very costly for
|
||||
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
|
||||
*
|
||||
* SdFat has a single 512 byte buffer for SD I/O so it must write the current
|
||||
* data block to the SD, read the directory block from the SD, update the
|
||||
* directory entry, write the directory block to the SD and read the data
|
||||
* block back into the buffer.
|
||||
*
|
||||
* The SD flash memory controller is not designed for this many rewrites
|
||||
* so performance may be reduced by more than a factor of 100.
|
||||
*
|
||||
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
|
||||
* all data to be written to the SD.
|
||||
*/
|
||||
#define ENDL_CALLS_FLUSH 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Allow use of deprecated functions if ALLOW_DEPRECATED_FUNCTIONS is nonzero
|
||||
*/
|
||||
#define ALLOW_DEPRECATED_FUNCTIONS 1
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Allow FAT12 volumes if FAT12_SUPPORT is nonzero.
|
||||
* FAT12 has not been well tested.
|
||||
*/
|
||||
#define FAT12_SUPPORT 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* SPI init rate for SD initialization commands. Must be 5 (F_CPU/64)
|
||||
* or 6 (F_CPU/128).
|
||||
*/
|
||||
#define SPI_SD_INIT_RATE 5
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Set the SS pin high for hardware SPI. If SS is chip select for another SPI
|
||||
* device this will disable that device during the SD init phase.
|
||||
*/
|
||||
#define SET_SPI_SS_HIGH 1
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Define MEGA_SOFT_SPI nonzero to use software SPI on Mega Arduinos.
|
||||
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||
*
|
||||
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||
* but many SD cards will fail with GPS Shield V1.0.
|
||||
*/
|
||||
#define MEGA_SOFT_SPI 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Set USE_SOFTWARE_SPI nonzero to always use software SPI.
|
||||
*/
|
||||
#define USE_SOFTWARE_SPI 0
|
||||
// define software SPI pins so Mega can use unmodified 168/328 shields
|
||||
/** Software SPI chip select pin for the SD */
|
||||
uint8_t const SOFT_SPI_CS_PIN = 10;
|
||||
/** Software SPI Master Out Slave In pin */
|
||||
uint8_t const SOFT_SPI_MOSI_PIN = 11;
|
||||
/** Software SPI Master In Slave Out pin */
|
||||
uint8_t const SOFT_SPI_MISO_PIN = 12;
|
||||
/** Software SPI Clock pin */
|
||||
uint8_t const SOFT_SPI_SCK_PIN = 13;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* The __cxa_pure_virtual function is an error handler that is invoked when
|
||||
* a pure virtual function is called.
|
||||
*/
|
||||
#define USE_CXA_PURE_VIRTUAL 1
|
||||
#endif // SdFatConfig_h
|
||||
|
||||
|
||||
#endif
|
||||
@@ -17,11 +17,14 @@
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FatStructs_h
|
||||
#define FatStructs_h
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef SdFatStructs_h
|
||||
#define SdFatStructs_h
|
||||
/**
|
||||
* \file
|
||||
* FAT file structures
|
||||
* \brief FAT file structures
|
||||
*/
|
||||
/*
|
||||
* mostly from Microsoft document fatgen103.doc
|
||||
@@ -32,6 +35,8 @@
|
||||
uint8_t const BOOTSIG0 = 0X55;
|
||||
/** Value for byte 511 of boot block or MBR */
|
||||
uint8_t const BOOTSIG1 = 0XAA;
|
||||
/** Value for bootSignature field int FAT/FAT32 boot sector */
|
||||
uint8_t const EXTENDED_BOOT_SIG = 0X29;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct partitionTable
|
||||
@@ -104,7 +109,7 @@ typedef struct partitionTable part_t;
|
||||
struct masterBootRecord {
|
||||
/** Code Area for master boot program. */
|
||||
uint8_t codeArea[440];
|
||||
/** Optional WindowsNT disk signature. May contain more boot code. */
|
||||
/** Optional Windows NT disk signature. May contain boot code. */
|
||||
uint32_t diskSignature;
|
||||
/** Usually zero but may be more boot code. */
|
||||
uint16_t usuallyZero;
|
||||
@@ -118,48 +123,60 @@ struct masterBootRecord {
|
||||
/** Type name for masterBootRecord */
|
||||
typedef struct masterBootRecord mbr_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct biosParmBlock
|
||||
/**
|
||||
* \struct fat_boot
|
||||
*
|
||||
* \brief Boot sector for a FAT12/FAT16 volume.
|
||||
*
|
||||
* \brief BIOS parameter block
|
||||
*
|
||||
* The BIOS parameter block describes the physical layout of a FAT volume.
|
||||
*/
|
||||
struct biosParmBlock {
|
||||
struct fat_boot {
|
||||
/**
|
||||
* The first three bytes of the boot sector must be valid,
|
||||
* executable x 86-based CPU instructions. This includes a
|
||||
* jump instruction that skips the next nonexecutable bytes.
|
||||
*/
|
||||
uint8_t jump[3];
|
||||
/**
|
||||
* This is typically a string of characters that identifies
|
||||
* the operating system that formatted the volume.
|
||||
*/
|
||||
char oemId[8];
|
||||
/**
|
||||
* Count of bytes per sector. This value may take on only the
|
||||
* following values: 512, 1024, 2048 or 4096
|
||||
* The size of a hardware sector. Valid decimal values for this
|
||||
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||
* the United States, the value of this field is 512.
|
||||
*/
|
||||
uint16_t bytesPerSector;
|
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a
|
||||
* power of 2 that is greater than 0. The legal values are
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128.
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||
*/
|
||||
uint8_t sectorsPerCluster;
|
||||
/**
|
||||
* Number of sectors before the first FAT.
|
||||
* This value must not be zero.
|
||||
* The number of sectors preceding the start of the first FAT,
|
||||
* including the boot sector. The value of this field is always 1.
|
||||
*/
|
||||
uint16_t reservedSectorCount;
|
||||
/** The count of FAT data structures on the volume. This field should
|
||||
* always contain the value 2 for any FAT volume of any type.
|
||||
/**
|
||||
* The number of copies of the FAT on the volume.
|
||||
* The value of this field is always 2.
|
||||
*/
|
||||
uint8_t fatCount;
|
||||
/**
|
||||
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||
* value should always specify a count that when multiplied by 32
|
||||
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||
* use the value 512.
|
||||
*/
|
||||
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||
* value should always specify a count that when multiplied by 32
|
||||
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||
* use the value 512.
|
||||
*/
|
||||
uint16_t rootDirEntryCount;
|
||||
/**
|
||||
* This field is the old 16-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||
* must be non-zero. For FAT32 volumes, this field must be 0. For
|
||||
* must be nonzero. For FAT32 volumes, this field must be 0. For
|
||||
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||
* totalSectors32 is 0 if the total sector count fits
|
||||
* (is less than 0x10000).
|
||||
@@ -168,7 +185,7 @@ struct biosParmBlock {
|
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is
|
||||
* no longer usually used for anything. 0xF8 is the standard value
|
||||
* for fixed (non-removable) media. For removable media, 0xF0 is
|
||||
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
*/
|
||||
uint8_t mediaType;
|
||||
@@ -179,23 +196,136 @@ struct biosParmBlock {
|
||||
*/
|
||||
uint16_t sectorsPerFat16;
|
||||
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t sectorsPerTrtack;
|
||||
uint16_t sectorsPerTrack;
|
||||
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t headCount;
|
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this
|
||||
* FAT volume. This field is generally only relevant for media
|
||||
* visible on interrupt 0x13.
|
||||
* visible on interrupt 0x13.
|
||||
*/
|
||||
uint32_t hidddenSectors;
|
||||
/**
|
||||
* This field is the new 32-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then
|
||||
* totalSectors16 must be non-zero.
|
||||
* totalSectors16 must be nonzero.
|
||||
*/
|
||||
uint32_t totalSectors32;
|
||||
/**
|
||||
* Related to the BIOS physical drive number. Floppy drives are
|
||||
* identified as 0x00 and physical hard disks are identified as
|
||||
* 0x80, regardless of the number of physical disk drives.
|
||||
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||
* call to specify the device to access. The value is only
|
||||
* relevant if the device is a boot device.
|
||||
*/
|
||||
uint8_t driveNumber;
|
||||
/** used by Windows NT - should be zero for FAT */
|
||||
uint8_t reserved1;
|
||||
/** 0X29 if next three fields are valid */
|
||||
uint8_t bootSignature;
|
||||
/**
|
||||
* A random serial number created when formatting a disk,
|
||||
* which helps to distinguish between disks.
|
||||
* Usually generated by combining date and time.
|
||||
*/
|
||||
uint32_t volumeSerialNumber;
|
||||
/**
|
||||
* A field once used to store the volume label. The volume label
|
||||
* is now stored as a special file in the root directory.
|
||||
*/
|
||||
char volumeLabel[11];
|
||||
/**
|
||||
* A field with a value of either FAT, FAT12 or FAT16,
|
||||
* depending on the disk format.
|
||||
*/
|
||||
char fileSystemType[8];
|
||||
/** X86 boot code */
|
||||
uint8_t bootCode[448];
|
||||
/** must be 0X55 */
|
||||
uint8_t bootSectorSig0;
|
||||
/** must be 0XAA */
|
||||
uint8_t bootSectorSig1;
|
||||
};
|
||||
/** Type name for FAT Boot Sector */
|
||||
typedef struct fat_boot fat_boot_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct fat32_boot
|
||||
*
|
||||
* \brief Boot sector for a FAT32 volume.
|
||||
*
|
||||
*/
|
||||
struct fat32_boot {
|
||||
/**
|
||||
* The first three bytes of the boot sector must be valid,
|
||||
* executable x 86-based CPU instructions. This includes a
|
||||
* jump instruction that skips the next nonexecutable bytes.
|
||||
*/
|
||||
uint8_t jump[3];
|
||||
/**
|
||||
* This is typically a string of characters that identifies
|
||||
* the operating system that formatted the volume.
|
||||
*/
|
||||
char oemId[8];
|
||||
/**
|
||||
* The size of a hardware sector. Valid decimal values for this
|
||||
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||
* the United States, the value of this field is 512.
|
||||
*/
|
||||
uint16_t bytesPerSector;
|
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a
|
||||
* power of 2 that is greater than 0. The legal values are
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||
*/
|
||||
uint8_t sectorsPerCluster;
|
||||
/**
|
||||
* The number of sectors preceding the start of the first FAT,
|
||||
* including the boot sector. Must not be zero
|
||||
*/
|
||||
uint16_t reservedSectorCount;
|
||||
/**
|
||||
* The number of copies of the FAT on the volume.
|
||||
* The value of this field is always 2.
|
||||
*/
|
||||
uint8_t fatCount;
|
||||
/**
|
||||
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
|
||||
*/
|
||||
uint16_t rootDirEntryCount;
|
||||
/**
|
||||
* For FAT32 volumes, this field must be 0.
|
||||
*/
|
||||
uint16_t totalSectors16;
|
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is
|
||||
* no longer usually used for anything. 0xF8 is the standard value
|
||||
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
*/
|
||||
uint8_t mediaType;
|
||||
/**
|
||||
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||
* contains the FAT size count.
|
||||
*/
|
||||
uint16_t sectorsPerFat16;
|
||||
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t sectorsPerTrack;
|
||||
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t headCount;
|
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this
|
||||
* FAT volume. This field is generally only relevant for media
|
||||
* visible on interrupt 0x13.
|
||||
*/
|
||||
uint32_t hidddenSectors;
|
||||
/**
|
||||
* Contains the total number of sectors in the FAT32 volume.
|
||||
*/
|
||||
uint32_t totalSectors32;
|
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||
*/
|
||||
uint32_t sectorsPerFat32;
|
||||
@@ -206,7 +336,8 @@ struct biosParmBlock {
|
||||
* Only valid if mirroring is disabled.
|
||||
* Bits 4-6 -- Reserved.
|
||||
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||
* -- 1 means only one FAT is active; it is the one referenced
|
||||
* in bits 0-3.
|
||||
* Bits 8-15 -- Reserved.
|
||||
*/
|
||||
uint16_t fat32Flags;
|
||||
@@ -226,7 +357,7 @@ struct biosParmBlock {
|
||||
*/
|
||||
uint16_t fat32FSInfo;
|
||||
/**
|
||||
* If non-zero, indicates the sector number in the reserved area
|
||||
* If nonzero, indicates the sector number in the reserved area
|
||||
* of the volume of a copy of the boot record. Usually 6.
|
||||
* No value other than 6 is recommended.
|
||||
*/
|
||||
@@ -236,34 +367,33 @@ struct biosParmBlock {
|
||||
* should always set all of the bytes of this field to 0.
|
||||
*/
|
||||
uint8_t fat32Reserved[12];
|
||||
};
|
||||
/** Type name for biosParmBlock */
|
||||
typedef struct biosParmBlock bpb_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct fat32BootSector
|
||||
*
|
||||
* \brief Boot sector for a FAT16 or FAT32 volume.
|
||||
*
|
||||
*/
|
||||
struct fat32BootSector {
|
||||
/** X86 jmp to boot program */
|
||||
uint8_t jmpToBootCode[3];
|
||||
/** informational only - don't depend on it */
|
||||
char oemName[8];
|
||||
/** BIOS Parameter Block */
|
||||
bpb_t bpb;
|
||||
/** for int0x13 use value 0X80 for hard drive */
|
||||
/**
|
||||
* Related to the BIOS physical drive number. Floppy drives are
|
||||
* identified as 0x00 and physical hard disks are identified as
|
||||
* 0x80, regardless of the number of physical disk drives.
|
||||
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||
* call to specify the device to access. The value is only
|
||||
* relevant if the device is a boot device.
|
||||
*/
|
||||
uint8_t driveNumber;
|
||||
/** used by Windows NT - should be zero for FAT */
|
||||
uint8_t reserved1;
|
||||
/** 0X29 if next three fields are valid */
|
||||
uint8_t bootSignature;
|
||||
/** usually generated by combining date and time */
|
||||
/**
|
||||
* A random serial number created when formatting a disk,
|
||||
* which helps to distinguish between disks.
|
||||
* Usually generated by combining date and time.
|
||||
*/
|
||||
uint32_t volumeSerialNumber;
|
||||
/** should match volume label in root dir */
|
||||
/**
|
||||
* A field once used to store the volume label. The volume label
|
||||
* is now stored as a special file in the root directory.
|
||||
*/
|
||||
char volumeLabel[11];
|
||||
/** informational only - don't depend on it */
|
||||
/**
|
||||
* A text field with a value of FAT32.
|
||||
*/
|
||||
char fileSystemType[8];
|
||||
/** X86 boot code */
|
||||
uint8_t bootCode[420];
|
||||
@@ -272,8 +402,54 @@ struct fat32BootSector {
|
||||
/** must be 0XAA */
|
||||
uint8_t bootSectorSig1;
|
||||
};
|
||||
/** Type name for FAT32 Boot Sector */
|
||||
typedef struct fat32_boot fat32_boot_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/** Lead signature for a FSINFO sector */
|
||||
uint32_t const FSINFO_LEAD_SIG = 0x41615252;
|
||||
/** Struct signature for a FSINFO sector */
|
||||
uint32_t const FSINFO_STRUCT_SIG = 0x61417272;
|
||||
/**
|
||||
* \struct fat32_fsinfo
|
||||
*
|
||||
* \brief FSINFO sector for a FAT32 volume.
|
||||
*
|
||||
*/
|
||||
struct fat32_fsinfo {
|
||||
/** must be 0X52, 0X52, 0X61, 0X41 */
|
||||
uint32_t leadSignature;
|
||||
/** must be zero */
|
||||
uint8_t reserved1[480];
|
||||
/** must be 0X72, 0X72, 0X41, 0X61 */
|
||||
uint32_t structSignature;
|
||||
/**
|
||||
* Contains the last known free cluster count on the volume.
|
||||
* If the value is 0xFFFFFFFF, then the free count is unknown
|
||||
* and must be computed. Any other value can be used, but is
|
||||
* not necessarily correct. It should be range checked at least
|
||||
* to make sure it is <= volume cluster count.
|
||||
*/
|
||||
uint32_t freeCount;
|
||||
/**
|
||||
* This is a hint for the FAT driver. It indicates the cluster
|
||||
* number at which the driver should start looking for free clusters.
|
||||
* If the value is 0xFFFFFFFF, then there is no hint and the driver
|
||||
* should start looking at cluster 2.
|
||||
*/
|
||||
uint32_t nextFree;
|
||||
/** must be zero */
|
||||
uint8_t reserved2[12];
|
||||
/** must be 0X00, 0X00, 0X55, 0XAA */
|
||||
uint8_t tailSignature[4];
|
||||
};
|
||||
/** Type name for FAT32 FSINFO Sector */
|
||||
typedef struct fat32_fsinfo fat32_fsinfo_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// End Of Chain values for FAT entries
|
||||
/** FAT12 end of chain value used by Microsoft. */
|
||||
uint16_t const FAT12EOC = 0XFFF;
|
||||
/** Minimum value for FAT12 EOC. Use to test for EOC. */
|
||||
uint16_t const FAT12EOC_MIN = 0XFF8;
|
||||
/** FAT16 end of chain value used by Microsoft. */
|
||||
uint16_t const FAT16EOC = 0XFFFF;
|
||||
/** Minimum value for FAT16 EOC. Use to test for EOC. */
|
||||
@@ -284,9 +460,6 @@ uint32_t const FAT32EOC = 0X0FFFFFFF;
|
||||
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
|
||||
/** Mask a for FAT32 entry. Entries are 28 bits. */
|
||||
uint32_t const FAT32MASK = 0X0FFFFFFF;
|
||||
|
||||
/** Type name for fat32BootSector */
|
||||
typedef struct fat32BootSector fbs_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct directoryEntry
|
||||
@@ -319,8 +492,8 @@ typedef struct fat32BootSector fbs_t;
|
||||
* The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||
*/
|
||||
struct directoryEntry {
|
||||
/**
|
||||
* Short 8.3 name.
|
||||
/** Short 8.3 name.
|
||||
*
|
||||
* The first eight bytes contain the file name with blank fill.
|
||||
* The last three bytes contain the file extension with blank fill.
|
||||
*/
|
||||
@@ -397,22 +570,41 @@ uint8_t const DIR_ATT_LONG_NAME = 0X0F;
|
||||
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
|
||||
/** defined attribute bits */
|
||||
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
|
||||
/** Directory entry is part of a long name */
|
||||
/** Directory entry is part of a long name
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for part of a long name else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||
}
|
||||
/** Mask for file/subdirectory tests */
|
||||
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||
/** Directory entry is for a file */
|
||||
/** Directory entry is for a file
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a normal file else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||
}
|
||||
/** Directory entry is for a subdirectory */
|
||||
/** Directory entry is for a subdirectory
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a subdirectory else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||
}
|
||||
/** Directory entry is for a file or subdirectory */
|
||||
/** Directory entry is for a file or subdirectory
|
||||
* \param[in] dir Pointer to a directory entry.
|
||||
*
|
||||
* \return true if the entry is for a normal file or subdirectory else false.
|
||||
*/
|
||||
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||
}
|
||||
#endif // FatStructs_h
|
||||
#endif // SdFatStructs_h
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
|
||||
#ifdef SDSUPPORT
|
||||
#include "SdFatUtil.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/** Amount of free RAM
|
||||
* \return The number of free bytes.
|
||||
*/
|
||||
int SdFatUtil::FreeRam() {
|
||||
extern int __bss_end;
|
||||
extern int* __brkval;
|
||||
int free_memory;
|
||||
if (reinterpret_cast<int>(__brkval) == 0) {
|
||||
// if no heap use from end of bss section
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(&__bss_end);
|
||||
} else {
|
||||
// use from top of stack to heap
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(__brkval);
|
||||
}
|
||||
return free_memory;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** %Print a string in flash memory.
|
||||
*
|
||||
* \param[in] pr Print object for output.
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
void SdFatUtil::print_P( PGM_P str) {
|
||||
for (uint8_t c; (c = pgm_read_byte(str)); str++) MYSERIAL.write(c);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** %Print a string in flash memory followed by a CR/LF.
|
||||
*
|
||||
* \param[in] pr Print object for output.
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
void SdFatUtil::println_P( PGM_P str) {
|
||||
print_P( str);
|
||||
MYSERIAL.println();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** %Print a string in flash memory to Serial.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
void SdFatUtil::SerialPrint_P(PGM_P str) {
|
||||
print_P(str);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** %Print a string in flash memory to Serial followed by a CR/LF.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
void SdFatUtil::SerialPrintln_P(PGM_P str) {
|
||||
println_P( str);
|
||||
}
|
||||
#endif
|
||||
+48
-70
@@ -1,70 +1,48 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdFatUtil_h
|
||||
#define SdFatUtil_h
|
||||
/**
|
||||
* \file
|
||||
* Useful utility functions.
|
||||
*/
|
||||
#include <WProgram.h>
|
||||
#include <avr/pgmspace.h>
|
||||
/** Store and print a string in flash memory.*/
|
||||
#define PgmPrint(x) SerialPrint_P(PSTR(x))
|
||||
/** Store and print a string in flash memory followed by a CR/LF.*/
|
||||
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
|
||||
/** Defined so doxygen works for function definitions. */
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
//------------------------------------------------------------------------------
|
||||
/** Return the number of bytes currently free in RAM. */
|
||||
static int FreeRam(void) {
|
||||
extern int __bss_end;
|
||||
extern int* __brkval;
|
||||
int free_memory;
|
||||
if (reinterpret_cast<int>(__brkval) == 0) {
|
||||
// if no heap use from end of bss section
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(&__bss_end);
|
||||
} else {
|
||||
// use from top of stack to heap
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(__brkval);
|
||||
}
|
||||
return free_memory;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* %Print a string in flash memory to the serial port.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
static NOINLINE void SerialPrint_P(PGM_P str) {
|
||||
for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* %Print a string in flash memory followed by a CR/LF.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
static NOINLINE void SerialPrintln_P(PGM_P str) {
|
||||
SerialPrint_P(str);
|
||||
Serial.println();
|
||||
}
|
||||
#endif // #define SdFatUtil_h
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef SdFatUtil_h
|
||||
#define SdFatUtil_h
|
||||
/**
|
||||
* \file
|
||||
* \brief Useful utility functions.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#include "MarlinSerial.h"
|
||||
/** Store and print a string in flash memory.*/
|
||||
#define PgmPrint(x) SerialPrint_P(PSTR(x))
|
||||
/** Store and print a string in flash memory followed by a CR/LF.*/
|
||||
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
|
||||
|
||||
namespace SdFatUtil {
|
||||
int FreeRam();
|
||||
void print_P( PGM_P str);
|
||||
void println_P( PGM_P str);
|
||||
void SerialPrint_P(PGM_P str);
|
||||
void SerialPrintln_P(PGM_P str);
|
||||
}
|
||||
|
||||
using namespace SdFatUtil; // NOLINT
|
||||
#endif // #define SdFatUtil_h
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,202 +0,0 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
\mainpage Arduino SdFat Library
|
||||
<CENTER>Copyright © 2009 by William Greiman
|
||||
</CENTER>
|
||||
|
||||
\section Intro Introduction
|
||||
The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
|
||||
file systems on SD flash memory cards. Standard SD and high capacity
|
||||
SDHC cards are supported.
|
||||
|
||||
The SdFat only supports short 8.3 names.
|
||||
|
||||
The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
|
||||
|
||||
The Sd2Card class supports access to standard SD cards and SDHC cards. Most
|
||||
applications will only need to call the Sd2Card::init() member function.
|
||||
|
||||
The SdVolume class supports FAT16 and FAT32 partitions. Most applications
|
||||
will only need to call the SdVolume::init() member function.
|
||||
|
||||
The SdFile class provides file access functions such as open(), read(),
|
||||
remove(), write(), close() and sync(). This class supports access to the root
|
||||
directory and subdirectories.
|
||||
|
||||
A number of example are provided in the SdFat/examples folder. These were
|
||||
developed to test SdFat and illustrate its use.
|
||||
|
||||
SdFat was developed for high speed data recording. SdFat was used to implement
|
||||
an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
|
||||
application uses special Sd2Card calls to write to contiguous files in raw mode.
|
||||
These functions reduce write latency so that audio can be recorded with the
|
||||
small amount of RAM in the Arduino.
|
||||
|
||||
\section SDcard SD\SDHC Cards
|
||||
|
||||
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
|
||||
most consumer devices use the 4-bit parallel SD protocol. A card that
|
||||
functions well on A PC or Mac may not work well on the Arduino.
|
||||
|
||||
Most cards have good SPI read performance but cards vary widely in SPI
|
||||
write performance. Write performance is limited by how efficiently the
|
||||
card manages internal erase/remapping operations. The Arduino cannot
|
||||
optimize writes to reduce erase operations because of its limit RAM.
|
||||
|
||||
SanDisk cards generally have good write performance. They seem to have
|
||||
more internal RAM buffering than other cards and therefore can limit
|
||||
the number of flash erase operations that the Arduino forces due to its
|
||||
limited RAM.
|
||||
|
||||
\section Hardware Hardware Configuration
|
||||
|
||||
SdFat was developed using an
|
||||
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
|
||||
<A HREF = "http://www.ladyada.net/make/waveshield/"> Wave Shield</A>.
|
||||
|
||||
The hardware interface to the SD card should not use a resistor based level
|
||||
shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
|
||||
rise times that are too slow for the edge detectors in many newer SD card
|
||||
controllers when resistor voltage dividers are used.
|
||||
|
||||
The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
|
||||
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
|
||||
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
|
||||
74LCX245.
|
||||
|
||||
If you are using a resistor based level shifter and are having problems try
|
||||
setting the SPI bus frequency to 4 MHz. This can be done by using
|
||||
card.init(SPI_HALF_SPEED) to initialize the SD card.
|
||||
|
||||
\section comment Bugs and Comments
|
||||
|
||||
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
|
||||
|
||||
\section SdFatClass SdFat Usage
|
||||
|
||||
SdFat uses a slightly restricted form of short names.
|
||||
Only printable ASCII characters are supported. No characters with code point
|
||||
values greater than 127 are allowed. Space is not allowed even though space
|
||||
was allowed in the API of early versions of DOS.
|
||||
|
||||
Short names are limited to 8 characters followed by an optional period (.)
|
||||
and extension of up to 3 characters. The characters may be any combination
|
||||
of letters and digits. The following special characters are also allowed:
|
||||
|
||||
$ % ' - _ @ ~ ` ! ( ) { } ^ # &
|
||||
|
||||
Short names are always converted to upper case and their original case
|
||||
value is lost.
|
||||
|
||||
\note
|
||||
The Arduino Print class uses character
|
||||
at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
|
||||
function to control when data is written to the SD card.
|
||||
|
||||
\par
|
||||
An application which writes to a file using \link Print::print() print()\endlink,
|
||||
\link Print::println() println() \endlink
|
||||
or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
|
||||
at the appropriate time to force data and directory information to be written
|
||||
to the SD Card. Data and directory information are also written to the SD card
|
||||
when \link SdFile::close() close() \endlink is called.
|
||||
|
||||
\par
|
||||
Applications must use care calling \link SdFile::sync() sync() \endlink
|
||||
since 2048 bytes of I/O is required to update file and
|
||||
directory information. This includes writing the current data block, reading
|
||||
the block that contains the directory entry for update, writing the directory
|
||||
block back and reading back the current data block.
|
||||
|
||||
It is possible to open a file with two or more instances of SdFile. A file may
|
||||
be corrupted if data is written to the file by more than one instance of SdFile.
|
||||
|
||||
\section HowTo How to format SD Cards as FAT Volumes
|
||||
|
||||
You should use a freshly formatted SD card for best performance. FAT
|
||||
file systems become slower if many files have been created and deleted.
|
||||
This is because the directory entry for a deleted file is marked as deleted,
|
||||
but is not deleted. When a new file is created, these entries must be scanned
|
||||
before creating the file, a flaw in the FAT design. Also files can become
|
||||
fragmented which causes reads and writes to be slower.
|
||||
|
||||
Microsoft operating systems support removable media formatted with a
|
||||
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
|
||||
in block zero.
|
||||
|
||||
Microsoft operating systems expect MBR formatted removable media
|
||||
to have only one partition. The first partition should be used.
|
||||
|
||||
Microsoft operating systems do not support partitioning SD flash cards.
|
||||
If you erase an SD card with a program like KillDisk, Most versions of
|
||||
Windows will format the card as a super floppy.
|
||||
|
||||
The best way to restore an SD card's format is to use SDFormatter
|
||||
which can be downloaded from:
|
||||
|
||||
http://www.sdcard.org/consumers/formatter/
|
||||
|
||||
SDFormatter aligns flash erase boundaries with file
|
||||
system structures which reduces write latency and file system overhead.
|
||||
|
||||
SDFormatter does not have an option for FAT type so it may format
|
||||
small cards as FAT12.
|
||||
|
||||
After the MBR is restored by SDFormatter you may need to reformat small
|
||||
cards that have been formatted FAT12 to force the volume type to be FAT16.
|
||||
|
||||
If you reformat the SD card with an OS utility, choose a cluster size that
|
||||
will result in:
|
||||
|
||||
4084 < CountOfClusters && CountOfClusters < 65525
|
||||
|
||||
The volume will then be FAT16.
|
||||
|
||||
If you are formatting an SD card on OS X or Linux, be sure to use the first
|
||||
partition. Format this partition with a cluster count in above range.
|
||||
|
||||
\section References References
|
||||
|
||||
Adafruit Industries:
|
||||
|
||||
http://www.adafruit.com/
|
||||
|
||||
http://www.ladyada.net/make/waveshield/
|
||||
|
||||
The Arduino site:
|
||||
|
||||
http://www.arduino.cc/
|
||||
|
||||
For more information about FAT file systems see:
|
||||
|
||||
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
|
||||
For information about using SD cards as SPI devices see:
|
||||
|
||||
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
|
||||
The ATmega328 datasheet:
|
||||
|
||||
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
|
||||
|
||||
|
||||
*/
|
||||
+92
-1252
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief SdFile class
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
|
||||
#ifdef SDSUPPORT
|
||||
#include "SdBaseFile.h"
|
||||
#include <Print.h>
|
||||
#ifndef SdFile_h
|
||||
#define SdFile_h
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdFile
|
||||
* \brief SdBaseFile with Print.
|
||||
*/
|
||||
class SdFile : public SdBaseFile, public Print {
|
||||
public:
|
||||
SdFile() {}
|
||||
SdFile(const char* name, uint8_t oflag);
|
||||
#if ARDUINO >= 100
|
||||
size_t write(uint8_t b);
|
||||
#else
|
||||
void write(uint8_t b);
|
||||
#endif
|
||||
|
||||
int16_t write(const void* buf, uint16_t nbyte);
|
||||
void write(const char* str);
|
||||
void write_P(PGM_P str);
|
||||
void writeln_P(PGM_P str);
|
||||
};
|
||||
#endif // SdFile_h
|
||||
|
||||
|
||||
#endif
|
||||
+280
-232
@@ -1,232 +1,280 @@
|
||||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdInfo_h
|
||||
#define SdInfo_h
|
||||
#include <stdint.h>
|
||||
// Based on the document:
|
||||
//
|
||||
// SD Specifications
|
||||
// Part 1
|
||||
// Physical Layer
|
||||
// Simplified Specification
|
||||
// Version 2.00
|
||||
// September 25, 2006
|
||||
//
|
||||
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card commands
|
||||
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||
uint8_t const CMD0 = 0X00;
|
||||
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||
uint8_t const CMD8 = 0X08;
|
||||
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||
uint8_t const CMD9 = 0X09;
|
||||
/** SEND_CID - read the card identification information (CID register) */
|
||||
uint8_t const CMD10 = 0X0A;
|
||||
/** SEND_STATUS - read the card status register */
|
||||
uint8_t const CMD13 = 0X0D;
|
||||
/** READ_BLOCK - read a single data block from the card */
|
||||
uint8_t const CMD17 = 0X11;
|
||||
/** WRITE_BLOCK - write a single data block to the card */
|
||||
uint8_t const CMD24 = 0X18;
|
||||
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||
uint8_t const CMD25 = 0X19;
|
||||
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||
uint8_t const CMD32 = 0X20;
|
||||
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||
range to be erased*/
|
||||
uint8_t const CMD33 = 0X21;
|
||||
/** ERASE - erase all previously selected blocks */
|
||||
uint8_t const CMD38 = 0X26;
|
||||
/** APP_CMD - escape for application specific command */
|
||||
uint8_t const CMD55 = 0X37;
|
||||
/** READ_OCR - read the OCR register of a card */
|
||||
uint8_t const CMD58 = 0X3A;
|
||||
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||
pre-erased before writing */
|
||||
uint8_t const ACMD23 = 0X17;
|
||||
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||
activates the card's initialization process */
|
||||
uint8_t const ACMD41 = 0X29;
|
||||
//------------------------------------------------------------------------------
|
||||
/** status for card in the ready state */
|
||||
uint8_t const R1_READY_STATE = 0X00;
|
||||
/** status for card in the idle state */
|
||||
uint8_t const R1_IDLE_STATE = 0X01;
|
||||
/** status bit for illegal command */
|
||||
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
|
||||
/** start data token for read or write single block*/
|
||||
uint8_t const DATA_START_BLOCK = 0XFE;
|
||||
/** stop token for write multiple blocks*/
|
||||
uint8_t const STOP_TRAN_TOKEN = 0XFD;
|
||||
/** start data token for write multiple blocks*/
|
||||
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||
/** mask for data response tokens after a write block operation */
|
||||
uint8_t const DATA_RES_MASK = 0X1F;
|
||||
/** write data accepted token */
|
||||
uint8_t const DATA_RES_ACCEPTED = 0X05;
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct CID {
|
||||
// byte 0
|
||||
uint8_t mid; // Manufacturer ID
|
||||
// byte 1-2
|
||||
char oid[2]; // OEM/Application ID
|
||||
// byte 3-7
|
||||
char pnm[5]; // Product name
|
||||
// byte 8
|
||||
unsigned prv_m : 4; // Product revision n.m
|
||||
unsigned prv_n : 4;
|
||||
// byte 9-12
|
||||
uint32_t psn; // Product serial number
|
||||
// byte 13
|
||||
unsigned mdt_year_high : 4; // Manufacturing date
|
||||
unsigned reserved : 4;
|
||||
// byte 14
|
||||
unsigned mdt_month : 4;
|
||||
unsigned mdt_year_low :4;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}cid_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// CSD for version 1.00 cards
|
||||
typedef struct CSDV1 {
|
||||
// byte 0
|
||||
unsigned reserved1 : 6;
|
||||
unsigned csd_ver : 2;
|
||||
// byte 1
|
||||
uint8_t taac;
|
||||
// byte 2
|
||||
uint8_t nsac;
|
||||
// byte 3
|
||||
uint8_t tran_speed;
|
||||
// byte 4
|
||||
uint8_t ccc_high;
|
||||
// byte 5
|
||||
unsigned read_bl_len : 4;
|
||||
unsigned ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned c_size_high : 2;
|
||||
unsigned reserved2 : 2;
|
||||
unsigned dsr_imp : 1;
|
||||
unsigned read_blk_misalign :1;
|
||||
unsigned write_blk_misalign : 1;
|
||||
unsigned read_bl_partial : 1;
|
||||
// byte 7
|
||||
uint8_t c_size_mid;
|
||||
// byte 8
|
||||
unsigned vdd_r_curr_max : 3;
|
||||
unsigned vdd_r_curr_min : 3;
|
||||
unsigned c_size_low :2;
|
||||
// byte 9
|
||||
unsigned c_size_mult_high : 2;
|
||||
unsigned vdd_w_cur_max : 3;
|
||||
unsigned vdd_w_curr_min : 3;
|
||||
// byte 10
|
||||
unsigned sector_size_high : 6;
|
||||
unsigned erase_blk_en : 1;
|
||||
unsigned c_size_mult_low : 1;
|
||||
// byte 11
|
||||
unsigned wp_grp_size : 7;
|
||||
unsigned sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned write_bl_len_high : 2;
|
||||
unsigned r2w_factor : 3;
|
||||
unsigned reserved3 : 2;
|
||||
unsigned wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned reserved4 : 5;
|
||||
unsigned write_partial : 1;
|
||||
unsigned write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned reserved5: 2;
|
||||
unsigned file_format : 2;
|
||||
unsigned tmp_write_protect : 1;
|
||||
unsigned perm_write_protect : 1;
|
||||
unsigned copy : 1;
|
||||
unsigned file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}csd1_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// CSD for version 2.00 cards
|
||||
typedef struct CSDV2 {
|
||||
// byte 0
|
||||
unsigned reserved1 : 6;
|
||||
unsigned csd_ver : 2;
|
||||
// byte 1
|
||||
uint8_t taac;
|
||||
// byte 2
|
||||
uint8_t nsac;
|
||||
// byte 3
|
||||
uint8_t tran_speed;
|
||||
// byte 4
|
||||
uint8_t ccc_high;
|
||||
// byte 5
|
||||
unsigned read_bl_len : 4;
|
||||
unsigned ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned reserved2 : 4;
|
||||
unsigned dsr_imp : 1;
|
||||
unsigned read_blk_misalign :1;
|
||||
unsigned write_blk_misalign : 1;
|
||||
unsigned read_bl_partial : 1;
|
||||
// byte 7
|
||||
unsigned reserved3 : 2;
|
||||
unsigned c_size_high : 6;
|
||||
// byte 8
|
||||
uint8_t c_size_mid;
|
||||
// byte 9
|
||||
uint8_t c_size_low;
|
||||
// byte 10
|
||||
unsigned sector_size_high : 6;
|
||||
unsigned erase_blk_en : 1;
|
||||
unsigned reserved4 : 1;
|
||||
// byte 11
|
||||
unsigned wp_grp_size : 7;
|
||||
unsigned sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned write_bl_len_high : 2;
|
||||
unsigned r2w_factor : 3;
|
||||
unsigned reserved5 : 2;
|
||||
unsigned wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned reserved6 : 5;
|
||||
unsigned write_partial : 1;
|
||||
unsigned write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned reserved7: 2;
|
||||
unsigned file_format : 2;
|
||||
unsigned tmp_write_protect : 1;
|
||||
unsigned perm_write_protect : 1;
|
||||
unsigned copy : 1;
|
||||
unsigned file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}csd2_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// union of old and new style CSD register
|
||||
union csd_t {
|
||||
csd1_t v1;
|
||||
csd2_t v2;
|
||||
};
|
||||
#endif // SdInfo_h
|
||||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#ifndef SdInfo_h
|
||||
#define SdInfo_h
|
||||
#include <stdint.h>
|
||||
// Based on the document:
|
||||
//
|
||||
// SD Specifications
|
||||
// Part 1
|
||||
// Physical Layer
|
||||
// Simplified Specification
|
||||
// Version 3.01
|
||||
// May 18, 2010
|
||||
//
|
||||
// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card commands
|
||||
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||
uint8_t const CMD0 = 0X00;
|
||||
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||
uint8_t const CMD8 = 0X08;
|
||||
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||
uint8_t const CMD9 = 0X09;
|
||||
/** SEND_CID - read the card identification information (CID register) */
|
||||
uint8_t const CMD10 = 0X0A;
|
||||
/** STOP_TRANSMISSION - end multiple block read sequence */
|
||||
uint8_t const CMD12 = 0X0C;
|
||||
/** SEND_STATUS - read the card status register */
|
||||
uint8_t const CMD13 = 0X0D;
|
||||
/** READ_SINGLE_BLOCK - read a single data block from the card */
|
||||
uint8_t const CMD17 = 0X11;
|
||||
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
|
||||
uint8_t const CMD18 = 0X12;
|
||||
/** WRITE_BLOCK - write a single data block to the card */
|
||||
uint8_t const CMD24 = 0X18;
|
||||
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||
uint8_t const CMD25 = 0X19;
|
||||
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||
uint8_t const CMD32 = 0X20;
|
||||
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||
range to be erased*/
|
||||
uint8_t const CMD33 = 0X21;
|
||||
/** ERASE - erase all previously selected blocks */
|
||||
uint8_t const CMD38 = 0X26;
|
||||
/** APP_CMD - escape for application specific command */
|
||||
uint8_t const CMD55 = 0X37;
|
||||
/** READ_OCR - read the OCR register of a card */
|
||||
uint8_t const CMD58 = 0X3A;
|
||||
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||
pre-erased before writing */
|
||||
uint8_t const ACMD23 = 0X17;
|
||||
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||
activates the card's initialization process */
|
||||
uint8_t const ACMD41 = 0X29;
|
||||
//------------------------------------------------------------------------------
|
||||
/** status for card in the ready state */
|
||||
uint8_t const R1_READY_STATE = 0X00;
|
||||
/** status for card in the idle state */
|
||||
uint8_t const R1_IDLE_STATE = 0X01;
|
||||
/** status bit for illegal command */
|
||||
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
|
||||
/** start data token for read or write single block*/
|
||||
uint8_t const DATA_START_BLOCK = 0XFE;
|
||||
/** stop token for write multiple blocks*/
|
||||
uint8_t const STOP_TRAN_TOKEN = 0XFD;
|
||||
/** start data token for write multiple blocks*/
|
||||
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||
/** mask for data response tokens after a write block operation */
|
||||
uint8_t const DATA_RES_MASK = 0X1F;
|
||||
/** write data accepted token */
|
||||
uint8_t const DATA_RES_ACCEPTED = 0X05;
|
||||
//------------------------------------------------------------------------------
|
||||
/** Card IDentification (CID) register */
|
||||
typedef struct CID {
|
||||
// byte 0
|
||||
/** Manufacturer ID */
|
||||
unsigned char mid;
|
||||
// byte 1-2
|
||||
/** OEM/Application ID */
|
||||
char oid[2];
|
||||
// byte 3-7
|
||||
/** Product name */
|
||||
char pnm[5];
|
||||
// byte 8
|
||||
/** Product revision least significant digit */
|
||||
unsigned char prv_m : 4;
|
||||
/** Product revision most significant digit */
|
||||
unsigned char prv_n : 4;
|
||||
// byte 9-12
|
||||
/** Product serial number */
|
||||
uint32_t psn;
|
||||
// byte 13
|
||||
/** Manufacturing date year low digit */
|
||||
unsigned char mdt_year_high : 4;
|
||||
/** not used */
|
||||
unsigned char reserved : 4;
|
||||
// byte 14
|
||||
/** Manufacturing date month */
|
||||
unsigned char mdt_month : 4;
|
||||
/** Manufacturing date year low digit */
|
||||
unsigned char mdt_year_low :4;
|
||||
// byte 15
|
||||
/** not used always 1 */
|
||||
unsigned char always1 : 1;
|
||||
/** CRC7 checksum */
|
||||
unsigned char crc : 7;
|
||||
}cid_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/** CSD for version 1.00 cards */
|
||||
typedef struct CSDV1 {
|
||||
// byte 0
|
||||
unsigned char reserved1 : 6;
|
||||
unsigned char csd_ver : 2;
|
||||
// byte 1
|
||||
unsigned char taac;
|
||||
// byte 2
|
||||
unsigned char nsac;
|
||||
// byte 3
|
||||
unsigned char tran_speed;
|
||||
// byte 4
|
||||
unsigned char ccc_high;
|
||||
// byte 5
|
||||
unsigned char read_bl_len : 4;
|
||||
unsigned char ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned char c_size_high : 2;
|
||||
unsigned char reserved2 : 2;
|
||||
unsigned char dsr_imp : 1;
|
||||
unsigned char read_blk_misalign :1;
|
||||
unsigned char write_blk_misalign : 1;
|
||||
unsigned char read_bl_partial : 1;
|
||||
// byte 7
|
||||
unsigned char c_size_mid;
|
||||
// byte 8
|
||||
unsigned char vdd_r_curr_max : 3;
|
||||
unsigned char vdd_r_curr_min : 3;
|
||||
unsigned char c_size_low :2;
|
||||
// byte 9
|
||||
unsigned char c_size_mult_high : 2;
|
||||
unsigned char vdd_w_cur_max : 3;
|
||||
unsigned char vdd_w_curr_min : 3;
|
||||
// byte 10
|
||||
unsigned char sector_size_high : 6;
|
||||
unsigned char erase_blk_en : 1;
|
||||
unsigned char c_size_mult_low : 1;
|
||||
// byte 11
|
||||
unsigned char wp_grp_size : 7;
|
||||
unsigned char sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned char write_bl_len_high : 2;
|
||||
unsigned char r2w_factor : 3;
|
||||
unsigned char reserved3 : 2;
|
||||
unsigned char wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned char reserved4 : 5;
|
||||
unsigned char write_partial : 1;
|
||||
unsigned char write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned char reserved5: 2;
|
||||
unsigned char file_format : 2;
|
||||
unsigned char tmp_write_protect : 1;
|
||||
unsigned char perm_write_protect : 1;
|
||||
unsigned char copy : 1;
|
||||
/** Indicates the file format on the card */
|
||||
unsigned char file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned char always1 : 1;
|
||||
unsigned char crc : 7;
|
||||
}csd1_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/** CSD for version 2.00 cards */
|
||||
typedef struct CSDV2 {
|
||||
// byte 0
|
||||
unsigned char reserved1 : 6;
|
||||
unsigned char csd_ver : 2;
|
||||
// byte 1
|
||||
/** fixed to 0X0E */
|
||||
unsigned char taac;
|
||||
// byte 2
|
||||
/** fixed to 0 */
|
||||
unsigned char nsac;
|
||||
// byte 3
|
||||
unsigned char tran_speed;
|
||||
// byte 4
|
||||
unsigned char ccc_high;
|
||||
// byte 5
|
||||
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
|
||||
unsigned char read_bl_len : 4;
|
||||
unsigned char ccc_low : 4;
|
||||
// byte 6
|
||||
/** not used */
|
||||
unsigned char reserved2 : 4;
|
||||
unsigned char dsr_imp : 1;
|
||||
/** fixed to 0 */
|
||||
unsigned char read_blk_misalign :1;
|
||||
/** fixed to 0 */
|
||||
unsigned char write_blk_misalign : 1;
|
||||
/** fixed to 0 - no partial read */
|
||||
unsigned char read_bl_partial : 1;
|
||||
// byte 7
|
||||
/** not used */
|
||||
unsigned char reserved3 : 2;
|
||||
/** high part of card size */
|
||||
unsigned char c_size_high : 6;
|
||||
// byte 8
|
||||
/** middle part of card size */
|
||||
unsigned char c_size_mid;
|
||||
// byte 9
|
||||
/** low part of card size */
|
||||
unsigned char c_size_low;
|
||||
// byte 10
|
||||
/** sector size is fixed at 64 KB */
|
||||
unsigned char sector_size_high : 6;
|
||||
/** fixed to 1 - erase single is supported */
|
||||
unsigned char erase_blk_en : 1;
|
||||
/** not used */
|
||||
unsigned char reserved4 : 1;
|
||||
// byte 11
|
||||
unsigned char wp_grp_size : 7;
|
||||
/** sector size is fixed at 64 KB */
|
||||
unsigned char sector_size_low : 1;
|
||||
// byte 12
|
||||
/** write_bl_len fixed for 512 byte blocks */
|
||||
unsigned char write_bl_len_high : 2;
|
||||
/** fixed value of 2 */
|
||||
unsigned char r2w_factor : 3;
|
||||
/** not used */
|
||||
unsigned char reserved5 : 2;
|
||||
/** fixed value of 0 - no write protect groups */
|
||||
unsigned char wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned char reserved6 : 5;
|
||||
/** always zero - no partial block read*/
|
||||
unsigned char write_partial : 1;
|
||||
/** write_bl_len fixed for 512 byte blocks */
|
||||
unsigned char write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned char reserved7: 2;
|
||||
/** Do not use always 0 */
|
||||
unsigned char file_format : 2;
|
||||
unsigned char tmp_write_protect : 1;
|
||||
unsigned char perm_write_protect : 1;
|
||||
unsigned char copy : 1;
|
||||
/** Do not use always 0 */
|
||||
unsigned char file_format_grp : 1;
|
||||
// byte 15
|
||||
/** not used always 1 */
|
||||
unsigned char always1 : 1;
|
||||
/** checksum */
|
||||
unsigned char crc : 7;
|
||||
}csd2_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/** union of old and new style CSD register */
|
||||
union csd_t {
|
||||
csd1_t v1;
|
||||
csd2_t v2;
|
||||
};
|
||||
#endif // SdInfo_h
|
||||
|
||||
#endif
|
||||
+405
-295
@@ -1,295 +1,405 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "SdFat.h"
|
||||
//------------------------------------------------------------------------------
|
||||
// raw block cache
|
||||
// init cacheBlockNumber_to invalid SD block number
|
||||
uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
|
||||
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
||||
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
|
||||
uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true
|
||||
uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT
|
||||
//------------------------------------------------------------------------------
|
||||
// find a contiguous group of clusters
|
||||
uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
|
||||
// start of group
|
||||
uint32_t bgnCluster;
|
||||
|
||||
// flag to save place to start next search
|
||||
uint8_t setStart;
|
||||
|
||||
// set search start cluster
|
||||
if (*curCluster) {
|
||||
// try to make file contiguous
|
||||
bgnCluster = *curCluster + 1;
|
||||
|
||||
// don't save new start location
|
||||
setStart = false;
|
||||
} else {
|
||||
// start at likely place for free cluster
|
||||
bgnCluster = allocSearchStart_;
|
||||
|
||||
// save next search start if one cluster
|
||||
setStart = 1 == count;
|
||||
}
|
||||
// end of group
|
||||
uint32_t endCluster = bgnCluster;
|
||||
|
||||
// last cluster of FAT
|
||||
uint32_t fatEnd = clusterCount_ + 1;
|
||||
|
||||
// search the FAT for free clusters
|
||||
for (uint32_t n = 0;; n++, endCluster++) {
|
||||
// can't find space checked all clusters
|
||||
if (n >= clusterCount_) return false;
|
||||
|
||||
// past end - start from beginning of FAT
|
||||
if (endCluster > fatEnd) {
|
||||
bgnCluster = endCluster = 2;
|
||||
}
|
||||
uint32_t f;
|
||||
if (!fatGet(endCluster, &f)) return false;
|
||||
|
||||
if (f != 0) {
|
||||
// cluster in use try next cluster as bgnCluster
|
||||
bgnCluster = endCluster + 1;
|
||||
} else if ((endCluster - bgnCluster + 1) == count) {
|
||||
// done - found space
|
||||
break;
|
||||
}
|
||||
}
|
||||
// mark end of chain
|
||||
if (!fatPutEOC(endCluster)) return false;
|
||||
|
||||
// link clusters
|
||||
while (endCluster > bgnCluster) {
|
||||
if (!fatPut(endCluster - 1, endCluster)) return false;
|
||||
endCluster--;
|
||||
}
|
||||
if (*curCluster != 0) {
|
||||
// connect chains
|
||||
if (!fatPut(*curCluster, bgnCluster)) return false;
|
||||
}
|
||||
// return first cluster number to caller
|
||||
*curCluster = bgnCluster;
|
||||
|
||||
// remember possible next free cluster
|
||||
if (setStart) allocSearchStart_ = bgnCluster + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdVolume::cacheFlush(void) {
|
||||
if (cacheDirty_) {
|
||||
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
|
||||
return false;
|
||||
}
|
||||
// mirror FAT tables
|
||||
if (cacheMirrorBlock_) {
|
||||
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
|
||||
return false;
|
||||
}
|
||||
cacheMirrorBlock_ = 0;
|
||||
}
|
||||
cacheDirty_ = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
|
||||
if (cacheBlockNumber_ != blockNumber) {
|
||||
if (!cacheFlush()) return false;
|
||||
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
}
|
||||
cacheDirty_ |= action;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// cache a zero block for blockNumber
|
||||
uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
|
||||
if (!cacheFlush()) return false;
|
||||
|
||||
// loop take less flash than memset(cacheBuffer_.data, 0, 512);
|
||||
for (uint16_t i = 0; i < 512; i++) {
|
||||
cacheBuffer_.data[i] = 0;
|
||||
}
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
cacheSetDirty();
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// return the size in bytes of a cluster chain
|
||||
uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const {
|
||||
uint32_t s = 0;
|
||||
do {
|
||||
if (!fatGet(cluster, &cluster)) return false;
|
||||
s += 512UL << clusterSizeShift_;
|
||||
} while (!isEOC(cluster));
|
||||
*size = s;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Fetch a FAT entry
|
||||
uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
|
||||
if (cluster > (clusterCount_ + 1)) return false;
|
||||
uint32_t lba = fatStartBlock_;
|
||||
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
||||
if (lba != cacheBlockNumber_) {
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
|
||||
}
|
||||
if (fatType_ == 16) {
|
||||
*value = cacheBuffer_.fat16[cluster & 0XFF];
|
||||
} else {
|
||||
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Store a FAT entry
|
||||
uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||
// error if reserved cluster
|
||||
if (cluster < 2) return false;
|
||||
|
||||
// error if not in FAT
|
||||
if (cluster > (clusterCount_ + 1)) return false;
|
||||
|
||||
// calculate block address for entry
|
||||
uint32_t lba = fatStartBlock_;
|
||||
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
|
||||
|
||||
if (lba != cacheBlockNumber_) {
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
|
||||
}
|
||||
// store entry
|
||||
if (fatType_ == 16) {
|
||||
cacheBuffer_.fat16[cluster & 0XFF] = value;
|
||||
} else {
|
||||
cacheBuffer_.fat32[cluster & 0X7F] = value;
|
||||
}
|
||||
cacheSetDirty();
|
||||
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// free a cluster chain
|
||||
uint8_t SdVolume::freeChain(uint32_t cluster) {
|
||||
// clear free cluster location
|
||||
allocSearchStart_ = 2;
|
||||
|
||||
do {
|
||||
uint32_t next;
|
||||
if (!fatGet(cluster, &next)) return false;
|
||||
|
||||
// free cluster
|
||||
if (!fatPut(cluster, 0)) return false;
|
||||
|
||||
cluster = next;
|
||||
} while (!isEOC(cluster));
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Initialize a FAT volume.
|
||||
*
|
||||
* \param[in] dev The SD card where the volume is located.
|
||||
*
|
||||
* \param[in] part The partition to be used. Legal values for \a part are
|
||||
* 1-4 to use the corresponding partition on a device formatted with
|
||||
* a MBR, Master Boot Record, or zero if the device is formatted as
|
||||
* a super floppy with the FAT boot sector in block zero.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. Reasons for
|
||||
* failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system in the specified partition or an I/O error.
|
||||
*/
|
||||
uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
|
||||
uint32_t volumeStartBlock = 0;
|
||||
sdCard_ = dev;
|
||||
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||
// if part > 0 assume mbr volume with partition table
|
||||
if (part) {
|
||||
if (part > 4)return false;
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
||||
part_t* p = &cacheBuffer_.mbr.part[part-1];
|
||||
if ((p->boot & 0X7F) !=0 ||
|
||||
p->totalSectors < 100 ||
|
||||
p->firstSector == 0) {
|
||||
// not a valid partition
|
||||
return false;
|
||||
}
|
||||
volumeStartBlock = p->firstSector;
|
||||
}
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
|
||||
bpb_t* bpb = &cacheBuffer_.fbs.bpb;
|
||||
if (bpb->bytesPerSector != 512 ||
|
||||
bpb->fatCount == 0 ||
|
||||
bpb->reservedSectorCount == 0 ||
|
||||
bpb->sectorsPerCluster == 0) {
|
||||
// not valid FAT volume
|
||||
return false;
|
||||
}
|
||||
fatCount_ = bpb->fatCount;
|
||||
blocksPerCluster_ = bpb->sectorsPerCluster;
|
||||
|
||||
// determine shift that is same as multiply by blocksPerCluster_
|
||||
clusterSizeShift_ = 0;
|
||||
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
|
||||
// error if not power of 2
|
||||
if (clusterSizeShift_++ > 7) return false;
|
||||
}
|
||||
blocksPerFat_ = bpb->sectorsPerFat16 ?
|
||||
bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
|
||||
|
||||
fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
|
||||
|
||||
// count for FAT16 zero for FAT32
|
||||
rootDirEntryCount_ = bpb->rootDirEntryCount;
|
||||
|
||||
// directory start for FAT16 dataStart for FAT32
|
||||
rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
|
||||
|
||||
// data start for FAT16 and FAT32
|
||||
dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);
|
||||
|
||||
// total blocks for FAT16 or FAT32
|
||||
uint32_t totalBlocks = bpb->totalSectors16 ?
|
||||
bpb->totalSectors16 : bpb->totalSectors32;
|
||||
// total data blocks
|
||||
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||
|
||||
// divide by cluster size to get cluster count
|
||||
clusterCount_ >>= clusterSizeShift_;
|
||||
|
||||
// FAT type is determined by cluster count
|
||||
if (clusterCount_ < 4085) {
|
||||
fatType_ = 12;
|
||||
} else if (clusterCount_ < 65525) {
|
||||
fatType_ = 16;
|
||||
} else {
|
||||
rootDirStart_ = bpb->fat32RootCluster;
|
||||
fatType_ = 32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#include "SdVolume.h"
|
||||
//------------------------------------------------------------------------------
|
||||
#if !USE_MULTIPLE_CARDS
|
||||
// raw block cache
|
||||
uint32_t SdVolume::cacheBlockNumber_; // current block number
|
||||
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
|
||||
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
|
||||
bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
|
||||
uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
|
||||
#endif // USE_MULTIPLE_CARDS
|
||||
//------------------------------------------------------------------------------
|
||||
// find a contiguous group of clusters
|
||||
bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
|
||||
// start of group
|
||||
uint32_t bgnCluster;
|
||||
// end of group
|
||||
uint32_t endCluster;
|
||||
// last cluster of FAT
|
||||
uint32_t fatEnd = clusterCount_ + 1;
|
||||
|
||||
// flag to save place to start next search
|
||||
bool setStart;
|
||||
|
||||
// set search start cluster
|
||||
if (*curCluster) {
|
||||
// try to make file contiguous
|
||||
bgnCluster = *curCluster + 1;
|
||||
|
||||
// don't save new start location
|
||||
setStart = false;
|
||||
} else {
|
||||
// start at likely place for free cluster
|
||||
bgnCluster = allocSearchStart_;
|
||||
|
||||
// save next search start if one cluster
|
||||
setStart = count == 1;
|
||||
}
|
||||
// end of group
|
||||
endCluster = bgnCluster;
|
||||
|
||||
// search the FAT for free clusters
|
||||
for (uint32_t n = 0;; n++, endCluster++) {
|
||||
// can't find space checked all clusters
|
||||
if (n >= clusterCount_) goto fail;
|
||||
|
||||
// past end - start from beginning of FAT
|
||||
if (endCluster > fatEnd) {
|
||||
bgnCluster = endCluster = 2;
|
||||
}
|
||||
uint32_t f;
|
||||
if (!fatGet(endCluster, &f)) goto fail;
|
||||
|
||||
if (f != 0) {
|
||||
// cluster in use try next cluster as bgnCluster
|
||||
bgnCluster = endCluster + 1;
|
||||
} else if ((endCluster - bgnCluster + 1) == count) {
|
||||
// done - found space
|
||||
break;
|
||||
}
|
||||
}
|
||||
// mark end of chain
|
||||
if (!fatPutEOC(endCluster)) goto fail;
|
||||
|
||||
// link clusters
|
||||
while (endCluster > bgnCluster) {
|
||||
if (!fatPut(endCluster - 1, endCluster)) goto fail;
|
||||
endCluster--;
|
||||
}
|
||||
if (*curCluster != 0) {
|
||||
// connect chains
|
||||
if (!fatPut(*curCluster, bgnCluster)) goto fail;
|
||||
}
|
||||
// return first cluster number to caller
|
||||
*curCluster = bgnCluster;
|
||||
|
||||
// remember possible next free cluster
|
||||
if (setStart) allocSearchStart_ = bgnCluster + 1;
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdVolume::cacheFlush() {
|
||||
if (cacheDirty_) {
|
||||
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
|
||||
goto fail;
|
||||
}
|
||||
// mirror FAT tables
|
||||
if (cacheMirrorBlock_) {
|
||||
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
|
||||
goto fail;
|
||||
}
|
||||
cacheMirrorBlock_ = 0;
|
||||
}
|
||||
cacheDirty_ = 0;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
|
||||
if (cacheBlockNumber_ != blockNumber) {
|
||||
if (!cacheFlush()) goto fail;
|
||||
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
}
|
||||
if (dirty) cacheDirty_ = true;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// return the size in bytes of a cluster chain
|
||||
bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
|
||||
uint32_t s = 0;
|
||||
do {
|
||||
if (!fatGet(cluster, &cluster)) goto fail;
|
||||
s += 512UL << clusterSizeShift_;
|
||||
} while (!isEOC(cluster));
|
||||
*size = s;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Fetch a FAT entry
|
||||
bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
|
||||
uint32_t lba;
|
||||
if (cluster > (clusterCount_ + 1)) goto fail;
|
||||
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||
uint16_t index = cluster;
|
||||
index += index >> 1;
|
||||
lba = fatStartBlock_ + (index >> 9);
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
|
||||
index &= 0X1FF;
|
||||
uint16_t tmp = cacheBuffer_.data[index];
|
||||
index++;
|
||||
if (index == 512) {
|
||||
if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
|
||||
index = 0;
|
||||
}
|
||||
tmp |= cacheBuffer_.data[index] << 8;
|
||||
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
|
||||
return true;
|
||||
}
|
||||
if (fatType_ == 16) {
|
||||
lba = fatStartBlock_ + (cluster >> 8);
|
||||
} else if (fatType_ == 32) {
|
||||
lba = fatStartBlock_ + (cluster >> 7);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
if (lba != cacheBlockNumber_) {
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
|
||||
}
|
||||
if (fatType_ == 16) {
|
||||
*value = cacheBuffer_.fat16[cluster & 0XFF];
|
||||
} else {
|
||||
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Store a FAT entry
|
||||
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||
uint32_t lba;
|
||||
// error if reserved cluster
|
||||
if (cluster < 2) goto fail;
|
||||
|
||||
// error if not in FAT
|
||||
if (cluster > (clusterCount_ + 1)) goto fail;
|
||||
|
||||
if (FAT12_SUPPORT && fatType_ == 12) {
|
||||
uint16_t index = cluster;
|
||||
index += index >> 1;
|
||||
lba = fatStartBlock_ + (index >> 9);
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
index &= 0X1FF;
|
||||
uint8_t tmp = value;
|
||||
if (cluster & 1) {
|
||||
tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
|
||||
}
|
||||
cacheBuffer_.data[index] = tmp;
|
||||
index++;
|
||||
if (index == 512) {
|
||||
lba++;
|
||||
index = 0;
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
}
|
||||
tmp = value >> 4;
|
||||
if (!(cluster & 1)) {
|
||||
tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
|
||||
}
|
||||
cacheBuffer_.data[index] = tmp;
|
||||
return true;
|
||||
}
|
||||
if (fatType_ == 16) {
|
||||
lba = fatStartBlock_ + (cluster >> 8);
|
||||
} else if (fatType_ == 32) {
|
||||
lba = fatStartBlock_ + (cluster >> 7);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
|
||||
// store entry
|
||||
if (fatType_ == 16) {
|
||||
cacheBuffer_.fat16[cluster & 0XFF] = value;
|
||||
} else {
|
||||
cacheBuffer_.fat32[cluster & 0X7F] = value;
|
||||
}
|
||||
// mirror second FAT
|
||||
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// free a cluster chain
|
||||
bool SdVolume::freeChain(uint32_t cluster) {
|
||||
uint32_t next;
|
||||
|
||||
// clear free cluster location
|
||||
allocSearchStart_ = 2;
|
||||
|
||||
do {
|
||||
if (!fatGet(cluster, &next)) goto fail;
|
||||
|
||||
// free cluster
|
||||
if (!fatPut(cluster, 0)) goto fail;
|
||||
|
||||
cluster = next;
|
||||
} while (!isEOC(cluster));
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Volume free space in clusters.
|
||||
*
|
||||
* \return Count of free clusters for success or -1 if an error occurs.
|
||||
*/
|
||||
int32_t SdVolume::freeClusterCount() {
|
||||
uint32_t free = 0;
|
||||
uint16_t n;
|
||||
uint32_t todo = clusterCount_ + 2;
|
||||
|
||||
if (fatType_ == 16) {
|
||||
n = 256;
|
||||
} else if (fatType_ == 32) {
|
||||
n = 128;
|
||||
} else {
|
||||
// put FAT12 here
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
|
||||
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
|
||||
if (todo < n) n = todo;
|
||||
if (fatType_ == 16) {
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
if (cacheBuffer_.fat16[i] == 0) free++;
|
||||
}
|
||||
} else {
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
if (cacheBuffer_.fat32[i] == 0) free++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return free;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Initialize a FAT volume.
|
||||
*
|
||||
* \param[in] dev The SD card where the volume is located.
|
||||
*
|
||||
* \param[in] part The partition to be used. Legal values for \a part are
|
||||
* 1-4 to use the corresponding partition on a device formatted with
|
||||
* a MBR, Master Boot Record, or zero if the device is formatted as
|
||||
* a super floppy with the FAT boot sector in block zero.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. Reasons for
|
||||
* failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system in the specified partition or an I/O error.
|
||||
*/
|
||||
bool SdVolume::init(Sd2Card* dev, uint8_t part) {
|
||||
uint32_t totalBlocks;
|
||||
uint32_t volumeStartBlock = 0;
|
||||
fat32_boot_t* fbs;
|
||||
|
||||
sdCard_ = dev;
|
||||
fatType_ = 0;
|
||||
allocSearchStart_ = 2;
|
||||
cacheDirty_ = 0; // cacheFlush() will write block if true
|
||||
cacheMirrorBlock_ = 0;
|
||||
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||
|
||||
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||
// if part > 0 assume mbr volume with partition table
|
||||
if (part) {
|
||||
if (part > 4)goto fail;
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
|
||||
part_t* p = &cacheBuffer_.mbr.part[part-1];
|
||||
if ((p->boot & 0X7F) !=0 ||
|
||||
p->totalSectors < 100 ||
|
||||
p->firstSector == 0) {
|
||||
// not a valid partition
|
||||
goto fail;
|
||||
}
|
||||
volumeStartBlock = p->firstSector;
|
||||
}
|
||||
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
|
||||
fbs = &cacheBuffer_.fbs32;
|
||||
if (fbs->bytesPerSector != 512 ||
|
||||
fbs->fatCount == 0 ||
|
||||
fbs->reservedSectorCount == 0 ||
|
||||
fbs->sectorsPerCluster == 0) {
|
||||
// not valid FAT volume
|
||||
goto fail;
|
||||
}
|
||||
fatCount_ = fbs->fatCount;
|
||||
blocksPerCluster_ = fbs->sectorsPerCluster;
|
||||
// determine shift that is same as multiply by blocksPerCluster_
|
||||
clusterSizeShift_ = 0;
|
||||
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
|
||||
// error if not power of 2
|
||||
if (clusterSizeShift_++ > 7) goto fail;
|
||||
}
|
||||
blocksPerFat_ = fbs->sectorsPerFat16 ?
|
||||
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
|
||||
|
||||
fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
|
||||
|
||||
// count for FAT16 zero for FAT32
|
||||
rootDirEntryCount_ = fbs->rootDirEntryCount;
|
||||
|
||||
// directory start for FAT16 dataStart for FAT32
|
||||
rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
|
||||
|
||||
// data start for FAT16 and FAT32
|
||||
dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
|
||||
|
||||
// total blocks for FAT16 or FAT32
|
||||
totalBlocks = fbs->totalSectors16 ?
|
||||
fbs->totalSectors16 : fbs->totalSectors32;
|
||||
// total data blocks
|
||||
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
|
||||
|
||||
// divide by cluster size to get cluster count
|
||||
clusterCount_ >>= clusterSizeShift_;
|
||||
|
||||
// FAT type is determined by cluster count
|
||||
if (clusterCount_ < 4085) {
|
||||
fatType_ = 12;
|
||||
if (!FAT12_SUPPORT) goto fail;
|
||||
} else if (clusterCount_ < 65525) {
|
||||
fatType_ = 16;
|
||||
} else {
|
||||
rootDirStart_ = fbs->fat32RootCluster;
|
||||
fatType_ = 32;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Marlin.h"
|
||||
#ifdef SDSUPPORT
|
||||
#ifndef SdVolume_h
|
||||
#define SdVolume_h
|
||||
/**
|
||||
* \file
|
||||
* \brief SdVolume class
|
||||
*/
|
||||
#include "SdFatConfig.h"
|
||||
#include "Sd2Card.h"
|
||||
#include "SdFatStructs.h"
|
||||
|
||||
//==============================================================================
|
||||
// SdVolume class
|
||||
/**
|
||||
* \brief Cache for an SD data block
|
||||
*/
|
||||
union cache_t {
|
||||
/** Used to access cached file data blocks. */
|
||||
uint8_t data[512];
|
||||
/** Used to access cached FAT16 entries. */
|
||||
uint16_t fat16[256];
|
||||
/** Used to access cached FAT32 entries. */
|
||||
uint32_t fat32[128];
|
||||
/** Used to access cached directory entries. */
|
||||
dir_t dir[16];
|
||||
/** Used to access a cached Master Boot Record. */
|
||||
mbr_t mbr;
|
||||
/** Used to access to a cached FAT boot sector. */
|
||||
fat_boot_t fbs;
|
||||
/** Used to access to a cached FAT32 boot sector. */
|
||||
fat32_boot_t fbs32;
|
||||
/** Used to access to a cached FAT32 FSINFO sector. */
|
||||
fat32_fsinfo_t fsinfo;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdVolume
|
||||
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||
*/
|
||||
class SdVolume {
|
||||
public:
|
||||
/** Create an instance of SdVolume */
|
||||
SdVolume() : fatType_(0) {}
|
||||
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||
* recorder to do raw write to the SD card. Not for normal apps.
|
||||
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||
*/
|
||||
cache_t* cacheClear() {
|
||||
if (!cacheFlush()) return 0;
|
||||
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||
return &cacheBuffer_;
|
||||
}
|
||||
/** Initialize a FAT volume. Try partition one first then try super
|
||||
* floppy format.
|
||||
*
|
||||
* \param[in] dev The Sd2Card where the volume is located.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. Reasons for
|
||||
* failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system or an I/O error.
|
||||
*/
|
||||
bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
|
||||
bool init(Sd2Card* dev, uint8_t part);
|
||||
|
||||
// inline functions that return volume info
|
||||
/** \return The volume's cluster size in blocks. */
|
||||
uint8_t blocksPerCluster() const {return blocksPerCluster_;}
|
||||
/** \return The number of blocks in one FAT. */
|
||||
uint32_t blocksPerFat() const {return blocksPerFat_;}
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount() const {return clusterCount_;}
|
||||
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||
uint8_t clusterSizeShift() const {return clusterSizeShift_;}
|
||||
/** \return The logical block number for the start of file data. */
|
||||
uint32_t dataStartBlock() const {return dataStartBlock_;}
|
||||
/** \return The number of FAT structures on the volume. */
|
||||
uint8_t fatCount() const {return fatCount_;}
|
||||
/** \return The logical block number for the start of the first FAT. */
|
||||
uint32_t fatStartBlock() const {return fatStartBlock_;}
|
||||
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||
uint8_t fatType() const {return fatType_;}
|
||||
int32_t freeClusterCount();
|
||||
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||
uint32_t rootDirEntryCount() const {return rootDirEntryCount_;}
|
||||
/** \return The logical block number for the start of the root directory
|
||||
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||
uint32_t rootDirStart() const {return rootDirStart_;}
|
||||
/** Sd2Card object for this volume
|
||||
* \return pointer to Sd2Card object.
|
||||
*/
|
||||
Sd2Card* sdCard() {return sdCard_;}
|
||||
/** Debug access to FAT table
|
||||
*
|
||||
* \param[in] n cluster number.
|
||||
* \param[out] v value of entry
|
||||
* \return true for success or false for failure
|
||||
*/
|
||||
bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);}
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
// Allow SdBaseFile access to SdVolume private data.
|
||||
friend class SdBaseFile;
|
||||
|
||||
// value for dirty argument in cacheRawBlock to indicate read from cache
|
||||
static bool const CACHE_FOR_READ = false;
|
||||
// value for dirty argument in cacheRawBlock to indicate write to cache
|
||||
static bool const CACHE_FOR_WRITE = true;
|
||||
|
||||
#if USE_MULTIPLE_CARDS
|
||||
cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
Sd2Card* sdCard_; // Sd2Card object for cache
|
||||
bool cacheDirty_; // cacheFlush() will write block if true
|
||||
uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
#else // USE_MULTIPLE_CARDS
|
||||
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
static Sd2Card* sdCard_; // Sd2Card object for cache
|
||||
static bool cacheDirty_; // cacheFlush() will write block if true
|
||||
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
#endif // USE_MULTIPLE_CARDS
|
||||
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||
uint32_t blocksPerFat_; // FAT size in blocks
|
||||
uint32_t clusterCount_; // clusters in one FAT
|
||||
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||
uint32_t dataStartBlock_; // first data block number
|
||||
uint8_t fatCount_; // number of FATs on volume
|
||||
uint32_t fatStartBlock_; // start block for first FAT
|
||||
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||
//----------------------------------------------------------------------------
|
||||
bool allocContiguous(uint32_t count, uint32_t* curCluster);
|
||||
uint8_t blockOfCluster(uint32_t position) const {
|
||||
return (position >> 9) & (blocksPerCluster_ - 1);}
|
||||
uint32_t clusterStartBlock(uint32_t cluster) const {
|
||||
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
|
||||
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
|
||||
return clusterStartBlock(cluster) + blockOfCluster(position);}
|
||||
cache_t *cache() {return &cacheBuffer_;}
|
||||
uint32_t cacheBlockNumber() {return cacheBlockNumber_;}
|
||||
#if USE_MULTIPLE_CARDS
|
||||
bool cacheFlush();
|
||||
bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||
#else // USE_MULTIPLE_CARDS
|
||||
static bool cacheFlush();
|
||||
static bool cacheRawBlock(uint32_t blockNumber, bool dirty);
|
||||
#endif // USE_MULTIPLE_CARDS
|
||||
// used by SdBaseFile write to assign cache to SD location
|
||||
void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) {
|
||||
cacheDirty_ = dirty;
|
||||
cacheBlockNumber_ = blockNumber;
|
||||
}
|
||||
void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||
bool chainSize(uint32_t beginCluster, uint32_t* size);
|
||||
bool fatGet(uint32_t cluster, uint32_t* value);
|
||||
bool fatPut(uint32_t cluster, uint32_t value);
|
||||
bool fatPutEOC(uint32_t cluster) {
|
||||
return fatPut(cluster, 0x0FFFFFFF);
|
||||
}
|
||||
bool freeChain(uint32_t cluster);
|
||||
bool isEOC(uint32_t cluster) const {
|
||||
if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN;
|
||||
if (fatType_ == 16) return cluster >= FAT16EOC_MIN;
|
||||
return cluster >= FAT32EOC_MIN;
|
||||
}
|
||||
bool readBlock(uint32_t block, uint8_t* dst) {
|
||||
return sdCard_->readBlock(block, dst);}
|
||||
bool writeBlock(uint32_t block, const uint8_t* dst) {
|
||||
return sdCard_->writeBlock(block, dst);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
|
||||
public:
|
||||
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev);
|
||||
* \param[in] dev The SD card where the volume is located.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool init(Sd2Card& dev) {return init(&dev);} // NOLINT
|
||||
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol);
|
||||
* \param[in] dev The SD card where the volume is located.
|
||||
* \param[in] part The partition to be used.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool init(Sd2Card& dev, uint8_t part) { // NOLINT
|
||||
return init(&dev, part);
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
};
|
||||
#endif // SdVolume
|
||||
#endif
|
||||
@@ -0,0 +1,634 @@
|
||||
#include "Marlin.h"
|
||||
#include "cardreader.h"
|
||||
#include "ultralcd.h"
|
||||
#include "stepper.h"
|
||||
#include "temperature.h"
|
||||
#include "language.h"
|
||||
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
|
||||
|
||||
CardReader::CardReader()
|
||||
{
|
||||
filesize = 0;
|
||||
sdpos = 0;
|
||||
sdprinting = false;
|
||||
cardOK = false;
|
||||
saving = false;
|
||||
autostart_atmillis=0;
|
||||
|
||||
autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
|
||||
lastnr=0;
|
||||
//power to SD reader
|
||||
#if SDPOWER > -1
|
||||
SET_OUTPUT(SDPOWER);
|
||||
WRITE(SDPOWER,HIGH);
|
||||
#endif //SDPOWER
|
||||
|
||||
autostart_atmillis=millis()+5000;
|
||||
}
|
||||
|
||||
char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
|
||||
{
|
||||
char *pos=buffer;
|
||||
for (uint8_t i = 0; i < 11; i++)
|
||||
{
|
||||
if (p.name[i] == ' ')continue;
|
||||
if (i == 8)
|
||||
{
|
||||
*pos++='.';
|
||||
}
|
||||
*pos++=p.name[i];
|
||||
}
|
||||
*pos++=0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void CardReader::lsDive(const char *prepend,SdFile parent)
|
||||
{
|
||||
dir_t p;
|
||||
uint8_t cnt=0;
|
||||
|
||||
while (parent.readDir(p) > 0)
|
||||
{
|
||||
if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
|
||||
{
|
||||
|
||||
char path[13*2];
|
||||
char lfilename[13];
|
||||
createFilename(lfilename,p);
|
||||
|
||||
path[0]=0;
|
||||
if(strlen(prepend)==0) //avoid leading / if already in prepend
|
||||
{
|
||||
strcat(path,"/");
|
||||
}
|
||||
strcat(path,prepend);
|
||||
strcat(path,lfilename);
|
||||
strcat(path,"/");
|
||||
|
||||
//Serial.print(path);
|
||||
|
||||
SdFile dir;
|
||||
if(!dir.open(parent,lfilename, O_READ))
|
||||
{
|
||||
if(lsAction==LS_SerialPrint)
|
||||
{
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
|
||||
SERIAL_ECHOLN(lfilename);
|
||||
}
|
||||
}
|
||||
lsDive(path,dir);
|
||||
//close done automatically by destructor of SdFile
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p.name[0] == DIR_NAME_FREE) break;
|
||||
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue;
|
||||
if ( p.name[0] == '.')
|
||||
{
|
||||
if ( p.name[1] != '.')
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
|
||||
filenameIsDir=DIR_IS_SUBDIR(&p);
|
||||
|
||||
|
||||
if(!filenameIsDir)
|
||||
{
|
||||
if(p.name[8]!='G') continue;
|
||||
if(p.name[9]=='~') continue;
|
||||
}
|
||||
//if(cnt++!=nr) continue;
|
||||
createFilename(filename,p);
|
||||
if(lsAction==LS_SerialPrint)
|
||||
{
|
||||
SERIAL_PROTOCOL(prepend);
|
||||
SERIAL_PROTOCOLLN(filename);
|
||||
}
|
||||
else if(lsAction==LS_Count)
|
||||
{
|
||||
nrFiles++;
|
||||
}
|
||||
else if(lsAction==LS_GetFilename)
|
||||
{
|
||||
if(cnt==nrFiles)
|
||||
return;
|
||||
cnt++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardReader::ls()
|
||||
{
|
||||
lsAction=LS_SerialPrint;
|
||||
if(lsAction==LS_Count)
|
||||
nrFiles=0;
|
||||
|
||||
root.rewind();
|
||||
lsDive("",root);
|
||||
}
|
||||
|
||||
|
||||
void CardReader::initsd()
|
||||
{
|
||||
cardOK = false;
|
||||
if(root.isOpen())
|
||||
root.close();
|
||||
if (!card.init(SPI_FULL_SPEED,SDSS))
|
||||
{
|
||||
//if (!card.init(SPI_HALF_SPEED,SDSS))
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
|
||||
}
|
||||
else if (!volume.init(&card))
|
||||
{
|
||||
SERIAL_ERROR_START;
|
||||
SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
|
||||
}
|
||||
else if (!root.openRoot(&volume))
|
||||
{
|
||||
SERIAL_ERROR_START;
|
||||
SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
|
||||
}
|
||||
else
|
||||
{
|
||||
cardOK = true;
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
|
||||
}
|
||||
workDir=root;
|
||||
curDir=&root;
|
||||
/*
|
||||
if(!workDir.openRoot(&volume))
|
||||
{
|
||||
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void CardReader::setroot()
|
||||
{
|
||||
/*if(!workDir.openRoot(&volume))
|
||||
{
|
||||
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
|
||||
}*/
|
||||
workDir=root;
|
||||
|
||||
curDir=&workDir;
|
||||
}
|
||||
void CardReader::release()
|
||||
{
|
||||
sdprinting = false;
|
||||
cardOK = false;
|
||||
}
|
||||
|
||||
void CardReader::startFileprint()
|
||||
{
|
||||
if(cardOK)
|
||||
{
|
||||
sdprinting = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CardReader::pauseSDPrint()
|
||||
{
|
||||
if(sdprinting)
|
||||
{
|
||||
sdprinting = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CardReader::openFile(char* name,bool read)
|
||||
{
|
||||
if(!cardOK)
|
||||
return;
|
||||
file.close();
|
||||
sdprinting = false;
|
||||
|
||||
|
||||
SdFile myDir;
|
||||
curDir=&root;
|
||||
char *fname=name;
|
||||
|
||||
char *dirname_start,*dirname_end;
|
||||
if(name[0]=='/')
|
||||
{
|
||||
dirname_start=strchr(name,'/')+1;
|
||||
while(dirname_start>0)
|
||||
{
|
||||
dirname_end=strchr(dirname_start,'/');
|
||||
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
|
||||
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
|
||||
if(dirname_end>0 && dirname_end>dirname_start)
|
||||
{
|
||||
char subdirname[13];
|
||||
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
|
||||
subdirname[dirname_end-dirname_start]=0;
|
||||
SERIAL_ECHOLN(subdirname);
|
||||
if(!myDir.open(curDir,subdirname,O_READ))
|
||||
{
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
|
||||
SERIAL_PROTOCOL(subdirname);
|
||||
SERIAL_PROTOCOLLNPGM(".");
|
||||
return;
|
||||
}
|
||||
else
|
||||
;//SERIAL_ECHOLN("dive ok");
|
||||
|
||||
curDir=&myDir;
|
||||
dirname_start=dirname_end+1;
|
||||
}
|
||||
else // the reminder after all /fsa/fdsa/ is the filename
|
||||
{
|
||||
fname=dirname_start;
|
||||
//SERIAL_ECHOLN("remaider");
|
||||
//SERIAL_ECHOLN(fname);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else //relative path
|
||||
{
|
||||
curDir=&workDir;
|
||||
}
|
||||
if(read)
|
||||
{
|
||||
if (file.open(curDir, fname, O_READ))
|
||||
{
|
||||
filesize = file.fileSize();
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
|
||||
SERIAL_PROTOCOL(fname);
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
|
||||
SERIAL_PROTOCOLLN(filesize);
|
||||
sdpos = 0;
|
||||
|
||||
SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
|
||||
LCD_MESSAGE(fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
|
||||
SERIAL_PROTOCOL(fname);
|
||||
SERIAL_PROTOCOLLNPGM(".");
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //write
|
||||
if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
|
||||
{
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
|
||||
SERIAL_PROTOCOL(fname);
|
||||
SERIAL_PROTOCOLLNPGM(".");
|
||||
}
|
||||
else
|
||||
{
|
||||
saving = true;
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
|
||||
SERIAL_PROTOCOLLN(name);
|
||||
LCD_MESSAGE(fname);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CardReader::removeFile(char* name)
|
||||
{
|
||||
if(!cardOK)
|
||||
return;
|
||||
file.close();
|
||||
sdprinting = false;
|
||||
|
||||
|
||||
SdFile myDir;
|
||||
curDir=&root;
|
||||
char *fname=name;
|
||||
|
||||
char *dirname_start,*dirname_end;
|
||||
if(name[0]=='/')
|
||||
{
|
||||
dirname_start=strchr(name,'/')+1;
|
||||
while(dirname_start>0)
|
||||
{
|
||||
dirname_end=strchr(dirname_start,'/');
|
||||
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
|
||||
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
|
||||
if(dirname_end>0 && dirname_end>dirname_start)
|
||||
{
|
||||
char subdirname[13];
|
||||
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
|
||||
subdirname[dirname_end-dirname_start]=0;
|
||||
SERIAL_ECHOLN(subdirname);
|
||||
if(!myDir.open(curDir,subdirname,O_READ))
|
||||
{
|
||||
SERIAL_PROTOCOLPGM("open failed, File: ");
|
||||
SERIAL_PROTOCOL(subdirname);
|
||||
SERIAL_PROTOCOLLNPGM(".");
|
||||
return;
|
||||
}
|
||||
else
|
||||
;//SERIAL_ECHOLN("dive ok");
|
||||
|
||||
curDir=&myDir;
|
||||
dirname_start=dirname_end+1;
|
||||
}
|
||||
else // the reminder after all /fsa/fdsa/ is the filename
|
||||
{
|
||||
fname=dirname_start;
|
||||
//SERIAL_ECHOLN("remaider");
|
||||
//SERIAL_ECHOLN(fname);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else //relative path
|
||||
{
|
||||
curDir=&workDir;
|
||||
}
|
||||
if (file.remove(curDir, fname))
|
||||
{
|
||||
SERIAL_PROTOCOLPGM("File deleted:");
|
||||
SERIAL_PROTOCOL(fname);
|
||||
sdpos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SERIAL_PROTOCOLPGM("Deletion failed, File: ");
|
||||
SERIAL_PROTOCOL(fname);
|
||||
SERIAL_PROTOCOLLNPGM(".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CardReader::getStatus()
|
||||
{
|
||||
if(cardOK){
|
||||
SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
|
||||
SERIAL_PROTOCOL(sdpos);
|
||||
SERIAL_PROTOCOLPGM("/");
|
||||
SERIAL_PROTOCOLLN(filesize);
|
||||
}
|
||||
else{
|
||||
SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
|
||||
}
|
||||
}
|
||||
void CardReader::write_command(char *buf)
|
||||
{
|
||||
char* begin = buf;
|
||||
char* npos = 0;
|
||||
char* end = buf + strlen(buf) - 1;
|
||||
|
||||
file.writeError = false;
|
||||
if((npos = strchr(buf, 'N')) != NULL)
|
||||
{
|
||||
begin = strchr(npos, ' ') + 1;
|
||||
end = strchr(npos, '*') - 1;
|
||||
}
|
||||
end[1] = '\r';
|
||||
end[2] = '\n';
|
||||
end[3] = '\0';
|
||||
file.write(begin);
|
||||
if (file.writeError)
|
||||
{
|
||||
SERIAL_ERROR_START;
|
||||
SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CardReader::checkautostart(bool force)
|
||||
{
|
||||
if(!force)
|
||||
{
|
||||
if(!autostart_stilltocheck)
|
||||
return;
|
||||
if(autostart_atmillis<millis())
|
||||
return;
|
||||
}
|
||||
autostart_stilltocheck=false;
|
||||
if(!cardOK)
|
||||
{
|
||||
initsd();
|
||||
if(!cardOK) //fail
|
||||
return;
|
||||
}
|
||||
|
||||
char autoname[30];
|
||||
sprintf(autoname,"auto%i.g",lastnr);
|
||||
for(int8_t i=0;i<(int)strlen(autoname);i++)
|
||||
autoname[i]=tolower(autoname[i]);
|
||||
dir_t p;
|
||||
|
||||
root.rewind();
|
||||
|
||||
bool found=false;
|
||||
while (root.readDir(p) > 0)
|
||||
{
|
||||
for(int8_t i=0;i<(int)strlen((char*)p.name);i++)
|
||||
p.name[i]=tolower(p.name[i]);
|
||||
//Serial.print((char*)p.name);
|
||||
//Serial.print(" ");
|
||||
//Serial.println(autoname);
|
||||
if(p.name[9]!='~') //skip safety copies
|
||||
if(strncmp((char*)p.name,autoname,5)==0)
|
||||
{
|
||||
char cmd[30];
|
||||
|
||||
sprintf(cmd,"M23 %s",autoname);
|
||||
enquecommand(cmd);
|
||||
enquecommand("M24");
|
||||
found=true;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
lastnr=-1;
|
||||
else
|
||||
lastnr++;
|
||||
}
|
||||
|
||||
void CardReader::closefile()
|
||||
{
|
||||
file.sync();
|
||||
file.close();
|
||||
saving = false;
|
||||
}
|
||||
|
||||
void CardReader::getfilename(const uint8_t nr)
|
||||
{
|
||||
curDir=&workDir;
|
||||
lsAction=LS_GetFilename;
|
||||
nrFiles=nr;
|
||||
curDir->rewind();
|
||||
lsDive("",*curDir);
|
||||
|
||||
}
|
||||
|
||||
uint16_t CardReader::getnrfilenames()
|
||||
{
|
||||
curDir=&workDir;
|
||||
lsAction=LS_Count;
|
||||
nrFiles=0;
|
||||
curDir->rewind();
|
||||
lsDive("",*curDir);
|
||||
//SERIAL_ECHOLN(nrFiles);
|
||||
return nrFiles;
|
||||
}
|
||||
|
||||
void CardReader::chdir(const char * relpath)
|
||||
{
|
||||
SdFile newfile;
|
||||
SdFile *parent=&root;
|
||||
|
||||
if(workDir.isOpen())
|
||||
parent=&workDir;
|
||||
|
||||
if(!newfile.open(*parent,relpath, O_READ))
|
||||
{
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
|
||||
SERIAL_ECHOLN(relpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
workDirParentParent=workDirParent;
|
||||
workDirParent=*parent;
|
||||
|
||||
workDir=newfile;
|
||||
}
|
||||
}
|
||||
|
||||
void CardReader::updir()
|
||||
{
|
||||
if(!workDir.isRoot())
|
||||
{
|
||||
workDir=workDirParent;
|
||||
workDirParent=workDirParentParent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CardReader::printingHasFinished()
|
||||
{
|
||||
st_synchronize();
|
||||
quickStop();
|
||||
sdprinting = false;
|
||||
if(SD_FINISHED_STEPPERRELEASE)
|
||||
{
|
||||
//finishAndDisableSteppers();
|
||||
enquecommand(SD_FINISHED_RELEASECOMMAND);
|
||||
}
|
||||
autotempShutdown();
|
||||
}
|
||||
void CardReader::fast_xfer(char* strchr_pointer)
|
||||
{
|
||||
char *pstr;
|
||||
boolean done = false;
|
||||
|
||||
//force heater pins low
|
||||
if(HEATER_0_PIN > -1) WRITE(HEATER_0_PIN,LOW);
|
||||
if(HEATER_BED_PIN > -1) WRITE(HEATER_BED_PIN,LOW);
|
||||
|
||||
lastxferchar = 1;
|
||||
xferbytes = 0;
|
||||
|
||||
pstr = strstr(strchr_pointer, " ");
|
||||
//pstr = strchr_pointer;
|
||||
|
||||
if(pstr == NULL)
|
||||
{
|
||||
SERIAL_ECHOLN("invalid command");
|
||||
return;
|
||||
}
|
||||
|
||||
*pstr = '\0';
|
||||
|
||||
//check mode (currently only RAW is supported
|
||||
if(strcmp(strchr_pointer, "RAW") != 0)
|
||||
{
|
||||
SERIAL_ECHOLN("Invalid transfer codec");
|
||||
return;
|
||||
}else{
|
||||
SERIAL_ECHOPGM("Selected codec: ");
|
||||
SERIAL_ECHOLN(strchr_pointer+4);
|
||||
}
|
||||
|
||||
if (!file.open(&root, pstr+1, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
|
||||
{
|
||||
SERIAL_ECHOPGM("open failed, File: ");
|
||||
SERIAL_ECHOLN(pstr+1);
|
||||
SERIAL_ECHOPGM(".");
|
||||
}else{
|
||||
SERIAL_ECHOPGM("Writing to file: ");
|
||||
SERIAL_ECHOLN(pstr+1);
|
||||
}
|
||||
|
||||
SERIAL_ECHOLN("ok");
|
||||
|
||||
//RAW transfer codec
|
||||
//Host sends \0 then up to SD_FAST_XFER_CHUNK_SIZE then \0
|
||||
//when host is done, it sends \0\0.
|
||||
//if a non \0 character is recieved at the beginning, host has failed somehow, kill the transfer.
|
||||
|
||||
//read SD_FAST_XFER_CHUNK_SIZE bytes (or until \0 is recieved)
|
||||
while(!done)
|
||||
{
|
||||
while(!MYSERIAL.available())
|
||||
{
|
||||
}
|
||||
if(MYSERIAL.peek() != 0)
|
||||
{
|
||||
//host has failed, this isn't a RAW chunk, it's an actual command
|
||||
file.sync();
|
||||
file.close();
|
||||
SERIAL_ECHOLN("Not RAW data");
|
||||
return;
|
||||
}
|
||||
//clear the initial 0
|
||||
MYSERIAL.read();
|
||||
for(int i=0;i<SD_FAST_XFER_CHUNK_SIZE+1;i++)
|
||||
{
|
||||
while(!MYSERIAL.available())
|
||||
{
|
||||
}
|
||||
lastxferchar = MYSERIAL.read();
|
||||
//buffer the data...
|
||||
fastxferbuffer[i] = lastxferchar;
|
||||
|
||||
xferbytes++;
|
||||
|
||||
if(lastxferchar == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(fastxferbuffer[0] != 0)
|
||||
{
|
||||
fastxferbuffer[SD_FAST_XFER_CHUNK_SIZE] = 0;
|
||||
file.write(fastxferbuffer);
|
||||
SERIAL_ECHOLN("ok");
|
||||
}else{
|
||||
SERIAL_ECHOPGM("Wrote ");
|
||||
SERIAL_ECHO(xferbytes);
|
||||
SERIAL_ECHOLN(" bytes.");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
file.sync();
|
||||
file.close();
|
||||
}
|
||||
|
||||
#endif //SDSUPPORT
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef CARDREADER_H
|
||||
#define CARDREADER_H
|
||||
|
||||
#ifdef SDSUPPORT
|
||||
|
||||
#include "SdFile.h"
|
||||
enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename};
|
||||
class CardReader
|
||||
{
|
||||
public:
|
||||
CardReader();
|
||||
|
||||
void initsd();
|
||||
void write_command(char *buf);
|
||||
//files auto[0-9].g on the sd card are performed in a row
|
||||
//this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
|
||||
|
||||
void checkautostart(bool x);
|
||||
void openFile(char* name,bool read);
|
||||
void removeFile(char* name);
|
||||
void closefile();
|
||||
void release();
|
||||
void startFileprint();
|
||||
void pauseSDPrint();
|
||||
void getStatus();
|
||||
void printingHasFinished();
|
||||
|
||||
void getfilename(const uint8_t nr);
|
||||
uint16_t getnrfilenames();
|
||||
|
||||
|
||||
void ls();
|
||||
void chdir(const char * relpath);
|
||||
void updir();
|
||||
void setroot();
|
||||
|
||||
void fast_xfer(char* strchr_pointer);
|
||||
|
||||
|
||||
FORCE_INLINE bool eof() { return sdpos>=filesize ;};
|
||||
FORCE_INLINE int16_t get() { sdpos = file.curPosition();return (int16_t)file.read();};
|
||||
FORCE_INLINE void setIndex(long index) {sdpos = index;file.seekSet(index);};
|
||||
FORCE_INLINE uint8_t percentDone(){if(!sdprinting) return 0; if(filesize) return sdpos*100/filesize; else return 0;};
|
||||
FORCE_INLINE char* getWorkDirName(){workDir.getFilename(filename);return filename;};
|
||||
|
||||
public:
|
||||
bool saving;
|
||||
bool sdprinting ;
|
||||
bool cardOK ;
|
||||
char filename[12];
|
||||
bool filenameIsDir;
|
||||
int lastnr; //last number of the autostart;
|
||||
char fastxferbuffer[SD_FAST_XFER_CHUNK_SIZE + 1];
|
||||
private:
|
||||
SdFile root,*curDir,workDir,workDirParent,workDirParentParent;
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile file;
|
||||
uint32_t filesize;
|
||||
//int16_t n;
|
||||
unsigned long autostart_atmillis;
|
||||
uint32_t sdpos ;
|
||||
|
||||
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
|
||||
|
||||
LsAction lsAction; //stored for recursion.
|
||||
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
|
||||
char* diveDirName;
|
||||
void lsDive(const char *prepend,SdFile parent);
|
||||
int lastxferchar;
|
||||
long xferbytes;
|
||||
};
|
||||
#define IS_SD_PRINTING (card.sdprinting)
|
||||
|
||||
#else
|
||||
|
||||
#define IS_SD_PRINTING (false)
|
||||
|
||||
#endif //SDSUPPORT
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
""" Generate the stepper delay lookup table for Marlin firmware. """
|
||||
|
||||
import argparse
|
||||
|
||||
__author__ = "Ben Gamari <bgamari@gmail.com>"
|
||||
__copyright__ = "Copyright 2012, Ben Gamari"
|
||||
__license__ = "GPL"
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('-f', '--cpu-freq', type=int, default=16, help='CPU clockrate in MHz (default=16)')
|
||||
parser.add_argument('-d', '--divider', type=int, default=8, help='Timer/counter pre-scale divider (default=8)')
|
||||
args = parser.parse_args()
|
||||
|
||||
cpu_freq = args.cpu_freq * 1000000
|
||||
timer_freq = cpu_freq / args.divider
|
||||
|
||||
print "#ifndef SPEED_LOOKUPTABLE_H"
|
||||
print "#define SPEED_LOOKUPTABLE_H"
|
||||
print
|
||||
print '#include "Marlin.h"'
|
||||
print
|
||||
|
||||
print "const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {"
|
||||
a = [ timer_freq / ((i*256)+(args.cpu_freq*2)) for i in range(256) ]
|
||||
b = [ a[i] - a[i+1] for i in range(255) ]
|
||||
b.append(b[-1])
|
||||
for i in range(32):
|
||||
print " ",
|
||||
for j in range(8):
|
||||
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
|
||||
print
|
||||
print "};"
|
||||
print
|
||||
|
||||
print "const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {"
|
||||
a = [ timer_freq / ((i*8)+(args.cpu_freq*2)) for i in range(256) ]
|
||||
b = [ a[i] - a[i+1] for i in range(255) ]
|
||||
b.append(b[-1])
|
||||
for i in range(32):
|
||||
print " ",
|
||||
for j in range(8):
|
||||
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
|
||||
print
|
||||
print "};"
|
||||
print
|
||||
|
||||
print "#endif"
|
||||
|
||||
+61
-37
@@ -1,63 +1,87 @@
|
||||
/*
|
||||
This code contibuted by Triffid_Hunter and modified by Kliment
|
||||
why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
This code contibuted by Triffid_Hunter and modified by Kliment
|
||||
why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
*/
|
||||
|
||||
#ifndef _ARDUINO_H
|
||||
#define _ARDUINO_H
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
/*
|
||||
utility functions
|
||||
utility functions
|
||||
*/
|
||||
|
||||
#ifndef MASK
|
||||
#ifndef MASK
|
||||
/// MASKING- returns \f$2^PIN\f$
|
||||
#define MASK(PIN) (1 << PIN)
|
||||
#define MASK(PIN) (1 << PIN)
|
||||
#endif
|
||||
|
||||
/*
|
||||
magic I/O routines
|
||||
|
||||
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
|
||||
magic I/O routines
|
||||
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
|
||||
*/
|
||||
|
||||
/// Read a pin
|
||||
#define _READ(IO) ((bool)(DIO ## IO ## _RPORT & MASK(DIO ## IO ## _PIN)))
|
||||
#define _READ(IO) ((bool)(DIO ## IO ## _RPORT & MASK(DIO ## IO ## _PIN)))
|
||||
/// write to a pin
|
||||
#define _WRITE(IO, v) do { if (v) {DIO ## IO ## _WPORT |= MASK(DIO ## IO ## _PIN); } else {DIO ## IO ## _WPORT &= ~MASK(DIO ## IO ## _PIN); }; } while (0)
|
||||
// On some boards pins > 0x100 are used. These are not converted to atomic actions. An critical section is needed.
|
||||
|
||||
#define _WRITE_NC(IO, v) do { if (v) {DIO ## IO ## _WPORT |= MASK(DIO ## IO ## _PIN); } else {DIO ## IO ## _WPORT &= ~MASK(DIO ## IO ## _PIN); }; } while (0)
|
||||
|
||||
#define _WRITE_C(IO, v) do { if (v) { \
|
||||
CRITICAL_SECTION_START; \
|
||||
{DIO ## IO ## _WPORT |= MASK(DIO ## IO ## _PIN); }\
|
||||
CRITICAL_SECTION_END; \
|
||||
}\
|
||||
else {\
|
||||
CRITICAL_SECTION_START; \
|
||||
{DIO ## IO ## _WPORT &= ~MASK(DIO ## IO ## _PIN); }\
|
||||
CRITICAL_SECTION_END; \
|
||||
}\
|
||||
}\
|
||||
while (0)
|
||||
|
||||
#define _WRITE(IO, v) do { if (&(DIO ## IO ## _RPORT) >= (uint8_t *)0x100) {_WRITE_C(IO, v); } else {_WRITE_NC(IO, v); }; } while (0)
|
||||
|
||||
/// toggle a pin
|
||||
#define _TOGGLE(IO) do {DIO ## IO ## _RPORT = MASK(DIO ## IO ## _PIN); } while (0)
|
||||
#define _TOGGLE(IO) do {DIO ## IO ## _RPORT = MASK(DIO ## IO ## _PIN); } while (0)
|
||||
|
||||
/// set pin as input
|
||||
#define _SET_INPUT(IO) do {DIO ## IO ## _DDR &= ~MASK(DIO ## IO ## _PIN); } while (0)
|
||||
#define _SET_INPUT(IO) do {DIO ## IO ## _DDR &= ~MASK(DIO ## IO ## _PIN); } while (0)
|
||||
/// set pin as output
|
||||
#define _SET_OUTPUT(IO) do {DIO ## IO ## _DDR |= MASK(DIO ## IO ## _PIN); } while (0)
|
||||
#define _SET_OUTPUT(IO) do {DIO ## IO ## _DDR |= MASK(DIO ## IO ## _PIN); } while (0)
|
||||
|
||||
/// check if pin is an input
|
||||
#define _GET_INPUT(IO) ((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) == 0)
|
||||
#define _GET_INPUT(IO) ((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) == 0)
|
||||
/// check if pin is an output
|
||||
#define _GET_OUTPUT(IO) ((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) != 0)
|
||||
#define _GET_OUTPUT(IO) ((DIO ## IO ## _DDR & MASK(DIO ## IO ## _PIN)) != 0)
|
||||
|
||||
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
/// check if pin is an timer
|
||||
#define _GET_TIMER(IO) ((DIO ## IO ## _PWM)
|
||||
|
||||
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
|
||||
/// Read a pin wrapper
|
||||
#define READ(IO) _READ(IO)
|
||||
#define READ(IO) _READ(IO)
|
||||
/// Write to a pin wrapper
|
||||
#define WRITE(IO, v) _WRITE(IO, v)
|
||||
#define WRITE(IO, v) _WRITE(IO, v)
|
||||
|
||||
/// toggle a pin wrapper
|
||||
#define TOGGLE(IO) _TOGGLE(IO)
|
||||
#define TOGGLE(IO) _TOGGLE(IO)
|
||||
|
||||
/// set pin as input wrapper
|
||||
#define SET_INPUT(IO) _SET_INPUT(IO)
|
||||
#define SET_INPUT(IO) _SET_INPUT(IO)
|
||||
/// set pin as output wrapper
|
||||
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
|
||||
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
|
||||
|
||||
/// check if pin is an input wrapper
|
||||
#define GET_INPUT(IO) _GET_INPUT(IO)
|
||||
#define GET_INPUT(IO) _GET_INPUT(IO)
|
||||
/// check if pin is an output wrapper
|
||||
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
|
||||
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
|
||||
|
||||
/// check if pin is an timer wrapper
|
||||
#define GET_TIMER(IO) _GET_TIMER(IO)
|
||||
|
||||
/*
|
||||
ports and functions
|
||||
@@ -400,7 +424,7 @@ pins
|
||||
#define PD7_PWM NULL
|
||||
#endif /* _AVR_ATmega{168,328,328P}__ */
|
||||
|
||||
#if defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
|
||||
#if defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__)
|
||||
// UART
|
||||
#define RXD DIO8
|
||||
#define TXD DIO9
|
||||
@@ -455,13 +479,13 @@ pins
|
||||
#define DIO3_RPORT PINB
|
||||
#define DIO3_WPORT PORTB
|
||||
#define DIO3_DDR DDRB
|
||||
#define DIO3_PWM &OCR0A
|
||||
#define DIO3_PWM OCR0A
|
||||
|
||||
#define DIO4_PIN PINB4
|
||||
#define DIO4_RPORT PINB
|
||||
#define DIO4_WPORT PORTB
|
||||
#define DIO4_DDR DDRB
|
||||
#define DIO4_PWM &OCR0B
|
||||
#define DIO4_PWM OCR0B
|
||||
|
||||
#define DIO5_PIN PINB5
|
||||
#define DIO5_RPORT PINB
|
||||
@@ -509,25 +533,25 @@ pins
|
||||
#define DIO12_RPORT PIND
|
||||
#define DIO12_WPORT PORTD
|
||||
#define DIO12_DDR DDRD
|
||||
#define DIO12_PWM NULL
|
||||
#define DIO12_PWM OCR1B
|
||||
|
||||
#define DIO13_PIN PIND5
|
||||
#define DIO13_RPORT PIND
|
||||
#define DIO13_WPORT PORTD
|
||||
#define DIO13_DDR DDRD
|
||||
#define DIO13_PWM NULL
|
||||
#define DIO13_PWM OCR1A
|
||||
|
||||
#define DIO14_PIN PIND6
|
||||
#define DIO14_RPORT PIND
|
||||
#define DIO14_WPORT PORTD
|
||||
#define DIO14_DDR DDRD
|
||||
#define DIO14_PWM &OCR2B
|
||||
#define DIO14_PWM OCR2B
|
||||
|
||||
#define DIO15_PIN PIND7
|
||||
#define DIO15_RPORT PIND
|
||||
#define DIO15_WPORT PORTD
|
||||
#define DIO15_DDR DDRD
|
||||
#define DIO15_PWM &OCR2A
|
||||
#define DIO15_PWM OCR2A
|
||||
|
||||
#define DIO16_PIN PINC0
|
||||
#define DIO16_RPORT PINC
|
||||
@@ -758,14 +782,14 @@ pins
|
||||
#define PB3_RPORT PINB
|
||||
#define PB3_WPORT PORTB
|
||||
#define PB3_DDR DDRB
|
||||
#define PB3_PWM &OCR0A
|
||||
#define PB3_PWM OCR0A
|
||||
|
||||
#undef PB4
|
||||
#define PB4_PIN PINB4
|
||||
#define PB4_RPORT PINB
|
||||
#define PB4_WPORT PORTB
|
||||
#define PB4_DDR DDRB
|
||||
#define PB4_PWM &OCR0B
|
||||
#define PB4_PWM OCR0B
|
||||
|
||||
#undef PB5
|
||||
#define PB5_PIN PINB5
|
||||
@@ -893,14 +917,14 @@ pins
|
||||
#define PD6_RPORT PIND
|
||||
#define PD6_WPORT PORTD
|
||||
#define PD6_DDR DDRD
|
||||
#define PD6_PWM &OCR2B
|
||||
#define PD6_PWM OCR2B
|
||||
|
||||
#undef PD7
|
||||
#define PD7_PIN PIND7
|
||||
#define PD7_RPORT PIND
|
||||
#define PD7_WPORT PORTD
|
||||
#define PD7_DDR DDRD
|
||||
#define PD7_PWM &OCR2A
|
||||
#define PD7_PWM OCR2A
|
||||
#endif /* _AVR_ATmega{644,644P,644PA}__ */
|
||||
|
||||
#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
|
||||
@@ -1904,7 +1928,7 @@ pins
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (__AVR_AT90USB1287__)
|
||||
#if defined (__AVR_AT90USB1287__) || defined (__AVR_AT90USB1286__)
|
||||
// SPI
|
||||
#define SCK DIO9
|
||||
#define MISO DIO11
|
||||
@@ -2555,4 +2579,4 @@ pins
|
||||
#error pins for this chip not defined in arduino.h! If you write an appropriate pin definition and have this firmware work on your chip, please submit a pull request
|
||||
#endif
|
||||
|
||||
#endif /* _ARDUINO_H */
|
||||
#endif /* _ARDUINO_H */
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
#ifndef LANGUAGE_H
|
||||
#define LANGUAGE_H
|
||||
|
||||
// Languages
|
||||
// 1 Custom (For you to add your own messages)
|
||||
// 2 English
|
||||
// 3 French (Waiting translation)
|
||||
// 4 German (Waiting translation)
|
||||
// 5 Etc
|
||||
|
||||
#define LANGUAGE_CHOICE 1 // Pick your language from the list above
|
||||
|
||||
#if LANGUAGE_CHOICE == 1
|
||||
|
||||
// LCD Menu Messages
|
||||
|
||||
#define WELCOME_MSG "Printer Ready."
|
||||
#define MSG_SD_INSERTED "Card inserted"
|
||||
#define MSG_SD_REMOVED "Card removed"
|
||||
#define MSG_MAIN " Main \003"
|
||||
#define MSG_AUTOSTART " Autostart"
|
||||
#define MSG_DISABLE_STEPPERS " Disable Steppers"
|
||||
#define MSG_AUTO_HOME " Auto Home"
|
||||
#define MSG_SET_ORIGIN " Set Origin"
|
||||
#define MSG_COOLDOWN " Cooldown"
|
||||
#define MSG_EXTRUDE " Extrude"
|
||||
#define MSG_PREHEAT_PLA " Preheat PLA"
|
||||
#define MSG_PREHEAT_ABS " Preheat ABS"
|
||||
#define MSG_MOVE_AXIS " Move Axis \x7E"
|
||||
#define MSG_SPEED " Speed:"
|
||||
#define MSG_NOZZLE " \002Nozzle:"
|
||||
#define MSG_BED " \002Bed:"
|
||||
#define MSG_FAN_SPEED " Fan speed:"
|
||||
#define MSG_FLOW " Flow:"
|
||||
#define MSG_CONTROL " Control \003"
|
||||
#define MSG_MIN " \002 Min:"
|
||||
#define MSG_MAX " \002 Max:"
|
||||
#define MSG_FACTOR " \002 Fact:"
|
||||
#define MSG_AUTOTEMP " Autotemp:"
|
||||
#define MSG_ON "On "
|
||||
#define MSG_OFF "Off"
|
||||
#define MSG_PID_P " PID-P: "
|
||||
#define MSG_PID_I " PID-I: "
|
||||
#define MSG_PID_D " PID-D: "
|
||||
#define MSG_PID_C " PID-C: "
|
||||
#define MSG_ACC " Acc:"
|
||||
#define MSG_VXY_JERK " Vxy-jerk: "
|
||||
#define MSG_VMAX " Vmax "
|
||||
#define MSG_X "x:"
|
||||
#define MSG_Y "y:"
|
||||
#define MSG_Z "z:"
|
||||
#define MSG_E "e:"
|
||||
#define MSG_VMIN " Vmin:"
|
||||
#define MSG_VTRAV_MIN " VTrav min:"
|
||||
#define MSG_AMAX " Amax "
|
||||
#define MSG_A_RETRACT " A-retract:"
|
||||
#define MSG_XSTEPS " Xsteps/mm:"
|
||||
#define MSG_YSTEPS " Ysteps/mm:"
|
||||
#define MSG_ZSTEPS " Zsteps/mm:"
|
||||
#define MSG_ESTEPS " Esteps/mm:"
|
||||
#define MSG_MAIN_WIDE " Main \003"
|
||||
#define MSG_TEMPERATURE_WIDE " Temperature \x7E"
|
||||
#define MSG_MOTION_WIDE " Motion \x7E"
|
||||
#define MSG_STORE_EPROM " Store memory"
|
||||
#define MSG_LOAD_EPROM " Load memory"
|
||||
#define MSG_RESTORE_FAILSAFE " Restore Failsafe"
|
||||
#define MSG_REFRESH "\004Refresh"
|
||||
#define MSG_WATCH " Watch \003"
|
||||
#define MSG_PREPARE " Prepare \x7E"
|
||||
#define MSG_PREPARE_ALT " Prepare \003"
|
||||
#define MSG_CONTROL_ARROW " Control \x7E"
|
||||
#define MSG_TUNE " Tune \x7E"
|
||||
#define MSG_STOP_PRINT " Stop Print \x7E"
|
||||
#define MSG_CARD_MENU " Card Menu \x7E"
|
||||
#define MSG_NO_CARD " No Card"
|
||||
#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Something is wrong in the MenuStructure."
|
||||
#define MSG_DWELL "Sleep..."
|
||||
#define MSG_USERWAIT "Wait for user..."
|
||||
#define MSG_NO_MOVE "No move."
|
||||
#define MSG_PART_RELEASE "Partial Release"
|
||||
#define MSG_KILLED "KILLED. "
|
||||
#define MSG_STOPPED "STOPPED. "
|
||||
#define MSG_PREHEAT_PLA " Preheat PLA"
|
||||
#define MSG_PREHEAT_ABS " Preheat ABS"
|
||||
#define MSG_STEPPER_RELEASED "Released."
|
||||
|
||||
|
||||
// Serial Console Messages
|
||||
|
||||
#define MSG_Enqueing "enqueing \""
|
||||
#define MSG_POWERUP "PowerUp"
|
||||
#define MSG_EXTERNAL_RESET " External Reset"
|
||||
#define MSG_BROWNOUT_RESET " Brown out Reset"
|
||||
#define MSG_WATCHDOG_RESET " Watchdog Reset"
|
||||
#define MSG_SOFTWARE_RESET " Software Reset"
|
||||
#define MSG_MARLIN "Marlin "
|
||||
#define MSG_AUTHOR " | Author: "
|
||||
#define MSG_CONFIGURATION_VER " Last Updated: "
|
||||
#define MSG_FREE_MEMORY " Free Memory: "
|
||||
#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
|
||||
#define MSG_OK "ok"
|
||||
#define MSG_FILE_SAVED "Done saving file."
|
||||
#define MSG_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line:"
|
||||
#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line:"
|
||||
#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line:"
|
||||
#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line:"
|
||||
#define MSG_FILE_PRINTED "Done printing file"
|
||||
#define MSG_BEGIN_FILE_LIST "Begin file list"
|
||||
#define MSG_END_FILE_LIST "End file list"
|
||||
#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder "
|
||||
#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder "
|
||||
#define MSG_ERR_NO_THERMISTORS "No thermistors - no temp"
|
||||
#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder "
|
||||
#define MSG_HEATING "Heating..."
|
||||
#define MSG_HEATING_COMPLETE "Heating done."
|
||||
#define MSG_BED_HEATING "Bed Heating."
|
||||
#define MSG_BED_DONE "Bed done."
|
||||
#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1\n"
|
||||
#define MSG_COUNT_X " Count X:"
|
||||
#define MSG_ERR_KILLED "Printer halted. kill() called !!"
|
||||
#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart!. (Temperature is reset. Set it before restarting)"
|
||||
#define MSG_RESEND "Resend:"
|
||||
#define MSG_UNKNOWN_COMMAND "Unknown command:\""
|
||||
#define MSG_ACTIVE_EXTRUDER "Active Extruder: "
|
||||
#define MSG_INVALID_EXTRUDER "Invalid extruder"
|
||||
#define MSG_X_MIN "x_min:"
|
||||
#define MSG_X_MAX "x_max:"
|
||||
#define MSG_Y_MIN "y_min:"
|
||||
#define MSG_Y_MAX "y_max:"
|
||||
#define MSG_Z_MIN "z_min:"
|
||||
#define MSG_Z_MAX "z_max:"
|
||||
|
||||
#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir"
|
||||
#define MSG_SD_INIT_FAIL "SD init fail"
|
||||
#define MSG_SD_VOL_INIT_FAIL "volume.init failed"
|
||||
#define MSG_SD_OPENROOT_FAIL "openRoot failed"
|
||||
#define MSG_SD_CARD_OK "SD card ok"
|
||||
#define MSG_SD_WORKDIR_FAIL "workDir open failed"
|
||||
#define MSG_SD_OPEN_FILE_FAIL "open failed, File: "
|
||||
#define MSG_SD_FILE_OPENED "File opened:"
|
||||
#define MSG_SD_SIZE " Size:"
|
||||
#define MSG_SD_FILE_SELECTED "File selected"
|
||||
#define MSG_SD_WRITE_TO_FILE "Writing to file: "
|
||||
#define MSG_SD_PRINTING_BYTE "SD printing byte "
|
||||
#define MSG_SD_NOT_PRINTING "Not SD printing"
|
||||
#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file"
|
||||
#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir:"
|
||||
|
||||
#define MSG_STEPPER_TO_HIGH "Steprate to high : "
|
||||
#define MSG_ENDSTOPS_HIT "endstops hit: "
|
||||
#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
|
||||
#define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
|
||||
|
||||
#endif
|
||||
#if LANGUAGE_CHOICE == 4
|
||||
|
||||
// LCD Menu Messages
|
||||
|
||||
#define WELCOME_MSG "MARLIN Ready."
|
||||
|
||||
#define MSG_SD_INSERTED "Card inserted"
|
||||
#define MSG_SD_REMOVED "Card removed"
|
||||
#define MSG_MAIN " Main \003"
|
||||
#define MSG_AUTOSTART " Autostart"
|
||||
#define MSG_DISABLE_STEPPERS " Stepper abschalten"
|
||||
#define MSG_AUTO_HOME " Auto Heim"
|
||||
#define MSG_SET_ORIGIN " Position setzen"
|
||||
#define MSG_PREHEAT_PLA " Aufheizen PLA"
|
||||
#define MSG_PREHEAT_ABS " Aufheizen ABS"
|
||||
#define MSG_COOLDOWN " Abkuehlen"
|
||||
#define MSG_EXTRUDE " Extrude"
|
||||
#define MSG_PREHEAT_PLA " Preheat PLA"
|
||||
#define MSG_PREHEAT_ABS " Preheat ABS"
|
||||
#define MSG_MOVE_AXIS " Move Axis \x7E"
|
||||
#define MSG_MOVE_AXIS " Achsen verfahren \x7E"
|
||||
#define MSG_SPEED " Geschw:"
|
||||
#define MSG_NOZZLE " \002Duese:"
|
||||
#define MSG_BED " \002Bett:"
|
||||
#define MSG_FAN_SPEED " Luefter geschw.:"
|
||||
#define MSG_FLOW " Fluss:"
|
||||
#define MSG_CONTROL " Kontrolle \003"
|
||||
#define MSG_MIN " \002 Min:"
|
||||
#define MSG_MAX " \002 Max:"
|
||||
#define MSG_FACTOR " \002 Faktor:"
|
||||
#define MSG_AUTOTEMP " AutoTemp:"
|
||||
#define MSG_ON "Ein "
|
||||
#define MSG_OFF "Aus "
|
||||
#define MSG_PID_P " PID-P: "
|
||||
#define MSG_PID_I " PID-I: "
|
||||
#define MSG_PID_D " PID-D: "
|
||||
#define MSG_PID_C " PID-C: "
|
||||
#define MSG_ACC " Acc:"
|
||||
#define MSG_VXY_JERK " Vxy-jerk: "
|
||||
#define MSG_VMAX " Vmax "
|
||||
#define MSG_X "x:"
|
||||
#define MSG_Y "y:"
|
||||
#define MSG_Z "z:"
|
||||
#define MSG_E "e:"
|
||||
#define MSG_VMIN " Vmin:"
|
||||
#define MSG_VTRAV_MIN " VTrav min:"
|
||||
#define MSG_AMAX " Amax "
|
||||
#define MSG_A_RETRACT " A-retract:"
|
||||
#define MSG_XSTEPS " Xsteps/mm:"
|
||||
#define MSG_YSTEPS " Ysteps/mm:"
|
||||
#define MSG_ZSTEPS " Zsteps/mm:"
|
||||
#define MSG_ESTEPS " Esteps/mm:"
|
||||
#define MSG_MAIN_WIDE " Main \003"
|
||||
#define MSG_TEMPERATURE_WIDE " Temperatur \x7E"
|
||||
#define MSG_MOTION_WIDE " Motion \x7E"
|
||||
#define MSG_STORE_EPROM " EPROM speichern"
|
||||
#define MSG_LOAD_EPROM " EPROM laden"
|
||||
#define MSG_RESTORE_FAILSAFE " Standard Konfig."
|
||||
#define MSG_REFRESH "\004Refresh"
|
||||
#define MSG_WATCH " Beobachten \003"
|
||||
#define MSG_PREPARE " Prepare \x7E"
|
||||
#define MSG_PREPARE_ALT " Prepare \003"
|
||||
#define MSG_CONTROL_ARROW " Control \x7E"
|
||||
#define MSG_TUNE " Tune \x7E"
|
||||
#define MSG_STOP_PRINT " Druck stoppen \x7E"
|
||||
#define MSG_CARD_MENU " SDKarten Menue \x7E"
|
||||
#define MSG_NO_CARD " Keine SDKarte"
|
||||
#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Fehler in der Menuestruktur."
|
||||
#define MSG_DWELL "DWELL..."
|
||||
#define MSG_NO_MOVE "No move."
|
||||
#define MSG_PART_RELEASE "Partial Release"
|
||||
#define MSG_KILLED "KILLED. "
|
||||
#define MSG_PREHEAT_PLA " Preheat PLA"
|
||||
#define MSG_PREHEAT_ABS " Preheat ABS"
|
||||
#define MSG_STEPPER_RELEASED "Released."
|
||||
|
||||
|
||||
// Serial Console Messages
|
||||
|
||||
#define MSG_Enqueing "enqueing \""
|
||||
#define MSG_POWERUP "PowerUp"
|
||||
#define MSG_EXTERNAL_RESET " External Reset"
|
||||
#define MSG_BROWNOUT_RESET " Brown out Reset"
|
||||
#define MSG_WATCHDOG_RESET " Watchdog Reset"
|
||||
#define MSG_SOFTWARE_RESET " Software Reset"
|
||||
#define MSG_MARLIN "Marlin: "
|
||||
#define MSG_AUTHOR " | Author: "
|
||||
#define MSG_CONFIGURATION_VER " Last Updated: "
|
||||
#define MSG_FREE_MEMORY " Free Memory: "
|
||||
#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
|
||||
#define MSG_OK "ok"
|
||||
#define MSG_FILE_SAVED "Done saving file."
|
||||
#define MSG_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line:"
|
||||
#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line:"
|
||||
#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line:"
|
||||
#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line:"
|
||||
#define MSG_FILE_PRINTED "Done printing file"
|
||||
#define MSG_BEGIN_FILE_LIST "Begin file list"
|
||||
#define MSG_END_FILE_LIST "End file list"
|
||||
#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder "
|
||||
#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder "
|
||||
#define MSG_ERR_NO_THERMISTORS "No thermistors - no temp"
|
||||
#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder "
|
||||
#define MSG_HEATING "Heating..."
|
||||
#define MSG_HEATING_COMPLETE "Heating done."
|
||||
#define MSG_BED_HEATING "Bed Heating."
|
||||
#define MSG_BED_DONE "Bed done."
|
||||
#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1\n"
|
||||
#define MSG_COUNT_X " Count X:"
|
||||
#define MSG_ERR_KILLED "Printer halted. kill() called !!"
|
||||
#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart!"
|
||||
#define MSG_RESEND "Resend:"
|
||||
#define MSG_UNKNOWN_COMMAND "Unknown command:\""
|
||||
#define MSG_ACTIVE_EXTRUDER "Active Extruder: "
|
||||
#define MSG_INVALID_EXTRUDER "Invalid extruder"
|
||||
#define MSG_X_MIN "x_min:"
|
||||
#define MSG_X_MAX "x_max:"
|
||||
#define MSG_Y_MIN "y_min:"
|
||||
#define MSG_Y_MAX "y_max:"
|
||||
#define MSG_Z_MIN "z_min:"
|
||||
#define MSG_Z_MAX "z_max:"
|
||||
|
||||
#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir"
|
||||
#define MSG_SD_INIT_FAIL "SD init fail"
|
||||
#define MSG_SD_VOL_INIT_FAIL "volume.init failed"
|
||||
#define MSG_SD_OPENROOT_FAIL "openRoot failed"
|
||||
#define MSG_SD_CARD_OK "SD card ok"
|
||||
#define MSG_SD_WORKDIR_FAIL "workDir open failed"
|
||||
#define MSG_SD_OPEN_FILE_FAIL "open failed, File: "
|
||||
#define MSG_SD_FILE_OPENED "File opened:"
|
||||
#define MSG_SD_SIZE " Size:"
|
||||
#define MSG_SD_FILE_SELECTED "File selected"
|
||||
#define MSG_SD_WRITE_TO_FILE "Writing to file: "
|
||||
#define MSG_SD_PRINTING_BYTE "SD printing byte "
|
||||
#define MSG_SD_NOT_PRINTING "Not SD printing"
|
||||
#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file"
|
||||
#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir:"
|
||||
|
||||
#define MSG_STEPPER_TO_HIGH "Steprate to high : "
|
||||
#define MSG_ENDSTOPS_HIT "endstops hit: "
|
||||
#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
|
||||
#define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
|
||||
|
||||
#endif
|
||||
#endif // ifndef LANGUAGE_H
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "led.h"
|
||||
#if (LED_PIN > -1)
|
||||
#include "Marlin.h"
|
||||
#include "temperature.h"
|
||||
|
||||
static unsigned long previous_millis_led=0;
|
||||
static unsigned long previous_millis_toggle=0;
|
||||
|
||||
void led_init()
|
||||
{
|
||||
SET_OUTPUT(LED_PIN);
|
||||
}
|
||||
|
||||
void led_status()
|
||||
{
|
||||
if (((millis() - previous_millis_led) < LED_UPDATE_INTERVAL))
|
||||
return;
|
||||
previous_millis_led=millis();
|
||||
if (degTargetHotend(active_extruder) > HEATER_0_MINTEMP)
|
||||
{
|
||||
if (((millis() - previous_millis_toggle) < LED_HOTEND_ACTIVE_FLASH))
|
||||
return;
|
||||
previous_millis_toggle=millis();
|
||||
TOGGLE(LED_PIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(LED_PIN, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //LED_PIN > -1
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef __LEDH
|
||||
|
||||
#define __LEDH
|
||||
#include "Marlin.h"
|
||||
|
||||
#if (LED_PIN > -1)
|
||||
void led_status();
|
||||
void led_init();
|
||||
|
||||
#define LED_UPDATE_INTERVAL 100
|
||||
#define LED_HOTEND_ACTIVE_FLASH 800
|
||||
#define LED_ERROR_FLASH 200
|
||||
#define LED_STATUS led_status()
|
||||
|
||||
#else //no led
|
||||
#define LED_STATUS
|
||||
FORCE_INLINE void led_status() {};
|
||||
#endif //LED_PIN > -1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
motion_control.c - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
Copyright (c) 2011 Sungeun K. Jeon
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "stepper.h"
|
||||
#include "planner.h"
|
||||
|
||||
// The arc is approximated by generating a huge number of tiny, linear segments. The length of each
|
||||
// segment is configured in settings.mm_per_arc_segment.
|
||||
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
|
||||
uint8_t axis_linear, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder)
|
||||
{
|
||||
// int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled();
|
||||
// plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
float center_axis1 = position[axis_1] + offset[axis_1];
|
||||
float linear_travel = target[axis_linear] - position[axis_linear];
|
||||
float extruder_travel = target[E_AXIS] - position[E_AXIS];
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
|
||||
if (angular_travel < 0) { angular_travel += 2*M_PI; }
|
||||
if (isclockwise) { angular_travel -= 2*M_PI; }
|
||||
|
||||
float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
|
||||
if (millimeters_of_travel < 0.001) { return; }
|
||||
uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT);
|
||||
if(segments == 0) segments = 1;
|
||||
|
||||
/*
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
// all segments.
|
||||
if (invert_feed_rate) { feed_rate *= segments; }
|
||||
*/
|
||||
float theta_per_segment = angular_travel/segments;
|
||||
float linear_per_segment = linear_travel/segments;
|
||||
float extruder_per_segment = extruder_travel/segments;
|
||||
|
||||
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
|
||||
and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
|
||||
r_T = [cos(phi) -sin(phi);
|
||||
sin(phi) cos(phi] * r ;
|
||||
|
||||
For arc generation, the center of the circle is the axis of rotation and the radius vector is
|
||||
defined from the circle center to the initial position. Each line segment is formed by successive
|
||||
vector rotations. This requires only two cos() and sin() computations to form the rotation
|
||||
matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since
|
||||
all double numbers are single precision on the Arduino. (True double precision will not have
|
||||
round off issues for CNC applications.) Single precision error can accumulate to be greater than
|
||||
tool precision in some cases. Therefore, arc path correction is implemented.
|
||||
|
||||
Small angle approximation may be used to reduce computation overhead further. This approximation
|
||||
holds for everything, but very small circles and large mm_per_arc_segment values. In other words,
|
||||
theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large
|
||||
to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for
|
||||
numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an
|
||||
issue for CNC machines with the single precision Arduino calculations.
|
||||
|
||||
This approximation also allows mc_arc to immediately insert a line segment into the planner
|
||||
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
|
||||
a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead.
|
||||
This is important when there are successive arc motions.
|
||||
*/
|
||||
// Vector rotation matrix values
|
||||
float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation
|
||||
float sin_T = theta_per_segment;
|
||||
|
||||
float arc_target[4];
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
uint16_t i;
|
||||
int8_t count = 0;
|
||||
|
||||
// Initialize the linear axis
|
||||
arc_target[axis_linear] = position[axis_linear];
|
||||
|
||||
// Initialize the extruder axis
|
||||
arc_target[E_AXIS] = position[E_AXIS];
|
||||
|
||||
for (i = 1; i<segments; i++) { // Increment (segments-1)
|
||||
|
||||
if (count < N_ARC_CORRECTION) {
|
||||
// Apply vector rotation matrix
|
||||
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
|
||||
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
|
||||
r_axis1 = r_axisi;
|
||||
count++;
|
||||
} else {
|
||||
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
|
||||
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
|
||||
cos_Ti = cos(i*theta_per_segment);
|
||||
sin_Ti = sin(i*theta_per_segment);
|
||||
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
|
||||
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// Update arc_target location
|
||||
arc_target[axis_0] = center_axis0 + r_axis0;
|
||||
arc_target[axis_1] = center_axis1 + r_axis1;
|
||||
arc_target[axis_linear] += linear_per_segment;
|
||||
arc_target[E_AXIS] += extruder_per_segment;
|
||||
|
||||
if (min_software_endstops) {
|
||||
if (arc_target[X_AXIS] < X_HOME_POS) arc_target[X_AXIS] = X_HOME_POS;
|
||||
if (arc_target[Y_AXIS] < Y_HOME_POS) arc_target[Y_AXIS] = Y_HOME_POS;
|
||||
if (arc_target[Z_AXIS] < Z_HOME_POS) arc_target[Z_AXIS] = Z_HOME_POS;
|
||||
}
|
||||
|
||||
if (max_software_endstops) {
|
||||
if (arc_target[X_AXIS] > X_MAX_LENGTH) arc_target[X_AXIS] = X_MAX_LENGTH;
|
||||
if (arc_target[Y_AXIS] > Y_MAX_LENGTH) arc_target[Y_AXIS] = Y_MAX_LENGTH;
|
||||
if (arc_target[Z_AXIS] > Z_MAX_LENGTH) arc_target[Z_AXIS] = Z_MAX_LENGTH;
|
||||
}
|
||||
plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, extruder);
|
||||
|
||||
}
|
||||
// Ensure last segment arrives at target location.
|
||||
plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder);
|
||||
|
||||
// plan_set_acceleration_manager_enabled(acceleration_manager_was_enabled);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
motion_control.h - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
Copyright (c) 2011 Sungeun K. Jeon
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef motion_control_h
|
||||
#define motion_control_h
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float *position, float *target, float *offset, unsigned char axis_0, unsigned char axis_1,
|
||||
unsigned char axis_linear, float feed_rate, float radius, unsigned char isclockwise, uint8_t extruder);
|
||||
|
||||
#endif
|
||||
+749
-218
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,812 @@
|
||||
/*
|
||||
planner.c - buffers movement commands and manages the acceleration profile plan
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
|
||||
|
||||
/*
|
||||
Reasoning behind the mathematics in this module (in the key of 'Mathematica'):
|
||||
|
||||
s == speed, a == acceleration, t == time, d == distance
|
||||
|
||||
Basic definitions:
|
||||
|
||||
Speed[s_, a_, t_] := s + (a*t)
|
||||
Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t]
|
||||
|
||||
Distance to reach a specific speed with a constant acceleration:
|
||||
|
||||
Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t]
|
||||
d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance()
|
||||
|
||||
Speed after a given distance of travel with constant acceleration:
|
||||
|
||||
Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t]
|
||||
m -> Sqrt[2 a d + s^2]
|
||||
|
||||
DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2]
|
||||
|
||||
When to start braking (di) to reach a specified destionation speed (s2) after accelerating
|
||||
from initial speed s1 without ever stopping at a plateau:
|
||||
|
||||
Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di]
|
||||
di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance()
|
||||
|
||||
IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a)
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "planner.h"
|
||||
#include "stepper.h"
|
||||
#include "temperature.h"
|
||||
#include "ultralcd.h"
|
||||
#include "language.h"
|
||||
#include "led.h"
|
||||
|
||||
//===========================================================================
|
||||
//=============================public variables ============================
|
||||
//===========================================================================
|
||||
|
||||
unsigned long minsegmenttime;
|
||||
float max_feedrate[4]; // set the max speeds
|
||||
float axis_steps_per_unit[4];
|
||||
unsigned long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software
|
||||
float minimumfeedrate;
|
||||
float acceleration; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
|
||||
float retract_acceleration; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
|
||||
float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
|
||||
float max_z_jerk;
|
||||
float max_e_jerk;
|
||||
float mintravelfeedrate;
|
||||
unsigned long axis_steps_per_sqr_second[NUM_AXIS];
|
||||
|
||||
// The current position of the tool in absolute steps
|
||||
long position[4]; //rescaled from extern when axis_steps_per_unit are changed by gcode
|
||||
static float previous_speed[4]; // Speed of previous path line segment
|
||||
static float previous_nominal_speed; // Nominal speed of previous path line segment
|
||||
|
||||
extern volatile int extrudemultiply; // Sets extrude multiply factor (in percent)
|
||||
|
||||
#ifdef AUTOTEMP
|
||||
float autotemp_max=250;
|
||||
float autotemp_min=210;
|
||||
float autotemp_factor=0.1;
|
||||
bool autotemp_enabled=false;
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//=================semi-private variables, used in inline functions =====
|
||||
//===========================================================================
|
||||
block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
|
||||
volatile unsigned char block_buffer_head; // Index of the next block to be pushed
|
||||
volatile unsigned char block_buffer_tail; // Index of the block to process now
|
||||
|
||||
//===========================================================================
|
||||
//=============================private variables ============================
|
||||
//===========================================================================
|
||||
#ifdef PREVENT_DANGEROUS_EXTRUDE
|
||||
bool allow_cold_extrude=false;
|
||||
#endif
|
||||
#ifdef XY_FREQUENCY_LIMIT
|
||||
// Used for the frequency limit
|
||||
static unsigned char old_direction_bits = 0; // Old direction bits. Used for speed calculations
|
||||
static long x_segment_time[3]={0,0,0}; // Segment times (in us). Used for speed calculations
|
||||
static long y_segment_time[3]={0,0,0};
|
||||
#endif
|
||||
|
||||
// Returns the index of the next block in the ring buffer
|
||||
// NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
|
||||
static int8_t next_block_index(int8_t block_index) {
|
||||
block_index++;
|
||||
if (block_index == BLOCK_BUFFER_SIZE) { block_index = 0; }
|
||||
return(block_index);
|
||||
}
|
||||
|
||||
|
||||
// Returns the index of the previous block in the ring buffer
|
||||
static int8_t prev_block_index(int8_t block_index) {
|
||||
if (block_index == 0) { block_index = BLOCK_BUFFER_SIZE; }
|
||||
block_index--;
|
||||
return(block_index);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//=============================functions ============================
|
||||
//===========================================================================
|
||||
|
||||
// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the
|
||||
// given acceleration:
|
||||
FORCE_INLINE float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
|
||||
{
|
||||
if (acceleration!=0) {
|
||||
return((target_rate*target_rate-initial_rate*initial_rate)/
|
||||
(2.0*acceleration));
|
||||
}
|
||||
else {
|
||||
return 0.0; // acceleration was 0, set acceleration distance to 0
|
||||
}
|
||||
}
|
||||
|
||||
// This function gives you the point at which you must start braking (at the rate of -acceleration) if
|
||||
// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
|
||||
// a total travel of distance. This can be used to compute the intersection point between acceleration and
|
||||
// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
|
||||
|
||||
FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
|
||||
{
|
||||
if (acceleration!=0) {
|
||||
return((2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/
|
||||
(4.0*acceleration) );
|
||||
}
|
||||
else {
|
||||
return 0.0; // acceleration was 0, set intersection distance to 0
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
|
||||
|
||||
void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor) {
|
||||
unsigned long initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
|
||||
unsigned long final_rate = ceil(block->nominal_rate*exit_factor); // (step/min)
|
||||
|
||||
// Limit minimal step rate (Otherwise the timer will overflow.)
|
||||
if(initial_rate <120) {initial_rate=120; }
|
||||
if(final_rate < 120) {final_rate=120; }
|
||||
|
||||
long acceleration = block->acceleration_st;
|
||||
int32_t accelerate_steps =
|
||||
ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration));
|
||||
int32_t decelerate_steps =
|
||||
floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration));
|
||||
|
||||
// Calculate the size of Plateau of Nominal Rate.
|
||||
int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
|
||||
|
||||
// Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
|
||||
// have to use intersection_distance() to calculate when to abort acceleration and start braking
|
||||
// in order to reach the final_rate exactly at the end of this block.
|
||||
if (plateau_steps < 0) {
|
||||
accelerate_steps = ceil(
|
||||
intersection_distance(block->initial_rate, block->final_rate, acceleration, block->step_event_count));
|
||||
accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
|
||||
accelerate_steps = min(accelerate_steps,block->step_event_count);
|
||||
plateau_steps = 0;
|
||||
}
|
||||
|
||||
#ifdef ADVANCE
|
||||
volatile long initial_advance = block->advance*entry_factor*entry_factor;
|
||||
volatile long final_advance = block->advance*exit_factor*exit_factor;
|
||||
#endif // ADVANCE
|
||||
|
||||
// block->accelerate_until = accelerate_steps;
|
||||
// block->decelerate_after = accelerate_steps+plateau_steps;
|
||||
CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section
|
||||
if(block->busy == false) { // Don't update variables if block is busy.
|
||||
block->accelerate_until = accelerate_steps;
|
||||
block->decelerate_after = accelerate_steps+plateau_steps;
|
||||
block->initial_rate = initial_rate;
|
||||
block->final_rate = final_rate;
|
||||
#ifdef ADVANCE
|
||||
block->initial_advance = initial_advance;
|
||||
block->final_advance = final_advance;
|
||||
#endif //ADVANCE
|
||||
}
|
||||
CRITICAL_SECTION_END;
|
||||
}
|
||||
|
||||
// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the
|
||||
// acceleration within the allotted distance.
|
||||
FORCE_INLINE float max_allowable_speed(float acceleration, float target_velocity, float distance) {
|
||||
return sqrt(target_velocity*target_velocity-2*acceleration*distance);
|
||||
}
|
||||
|
||||
// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks.
|
||||
// This method will calculate the junction jerk as the euclidean distance between the nominal
|
||||
// velocities of the respective blocks.
|
||||
//inline float junction_jerk(block_t *before, block_t *after) {
|
||||
// return sqrt(
|
||||
// pow((before->speed_x-after->speed_x), 2)+pow((before->speed_y-after->speed_y), 2));
|
||||
//}
|
||||
|
||||
|
||||
// The kernel called by planner_recalculate() when scanning the plan from last to first entry.
|
||||
void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) {
|
||||
if(!current) { return; }
|
||||
|
||||
if (next) {
|
||||
// If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
|
||||
// If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
|
||||
// check for maximum allowable speed reductions to ensure maximum possible planned speed.
|
||||
if (current->entry_speed != current->max_entry_speed) {
|
||||
|
||||
// If nominal length true, max junction speed is guaranteed to be reached. Only compute
|
||||
// for max allowable speed if block is decelerating and nominal length is false.
|
||||
if ((!current->nominal_length_flag) && (current->max_entry_speed > next->entry_speed)) {
|
||||
current->entry_speed = min( current->max_entry_speed,
|
||||
max_allowable_speed(-current->acceleration,next->entry_speed,current->millimeters));
|
||||
} else {
|
||||
current->entry_speed = current->max_entry_speed;
|
||||
}
|
||||
current->recalculate_flag = true;
|
||||
|
||||
}
|
||||
} // Skip last block. Already initialized and set for recalculation.
|
||||
}
|
||||
|
||||
// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
|
||||
// implements the reverse pass.
|
||||
void planner_reverse_pass() {
|
||||
uint8_t block_index = block_buffer_head;
|
||||
if(((block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1)) > 3) {
|
||||
block_index = (block_buffer_head - 3) & (BLOCK_BUFFER_SIZE - 1);
|
||||
block_t *block[3] = { NULL, NULL, NULL };
|
||||
while(block_index != block_buffer_tail) {
|
||||
block_index = prev_block_index(block_index);
|
||||
block[2]= block[1];
|
||||
block[1]= block[0];
|
||||
block[0] = &block_buffer[block_index];
|
||||
planner_reverse_pass_kernel(block[0], block[1], block[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The kernel called by planner_recalculate() when scanning the plan from first to last entry.
|
||||
void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) {
|
||||
if(!previous) { return; }
|
||||
|
||||
// If the previous block is an acceleration block, but it is not long enough to complete the
|
||||
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
|
||||
// speeds have already been reset, maximized, and reverse planned by reverse planner.
|
||||
// If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
|
||||
if (!previous->nominal_length_flag) {
|
||||
if (previous->entry_speed < current->entry_speed) {
|
||||
double entry_speed = min( current->entry_speed,
|
||||
max_allowable_speed(-previous->acceleration,previous->entry_speed,previous->millimeters) );
|
||||
|
||||
// Check for junction speed change
|
||||
if (current->entry_speed != entry_speed) {
|
||||
current->entry_speed = entry_speed;
|
||||
current->recalculate_flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
|
||||
// implements the forward pass.
|
||||
void planner_forward_pass() {
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
block_t *block[3] = { NULL, NULL, NULL };
|
||||
|
||||
while(block_index != block_buffer_head) {
|
||||
block[0] = block[1];
|
||||
block[1] = block[2];
|
||||
block[2] = &block_buffer[block_index];
|
||||
planner_forward_pass_kernel(block[0],block[1],block[2]);
|
||||
block_index = next_block_index(block_index);
|
||||
}
|
||||
planner_forward_pass_kernel(block[1], block[2], NULL);
|
||||
}
|
||||
|
||||
// Recalculates the trapezoid speed profiles for all blocks in the plan according to the
|
||||
// entry_factor for each junction. Must be called by planner_recalculate() after
|
||||
// updating the blocks.
|
||||
void planner_recalculate_trapezoids() {
|
||||
int8_t block_index = block_buffer_tail;
|
||||
block_t *current;
|
||||
block_t *next = NULL;
|
||||
|
||||
while(block_index != block_buffer_head) {
|
||||
current = next;
|
||||
next = &block_buffer[block_index];
|
||||
if (current) {
|
||||
// Recalculate if current block entry or exit junction speed has changed.
|
||||
if (current->recalculate_flag || next->recalculate_flag) {
|
||||
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
|
||||
calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed,
|
||||
next->entry_speed/current->nominal_speed);
|
||||
current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
|
||||
}
|
||||
}
|
||||
block_index = next_block_index( block_index );
|
||||
}
|
||||
// Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
|
||||
if(next != NULL) {
|
||||
calculate_trapezoid_for_block(next, next->entry_speed/next->nominal_speed,
|
||||
MINIMUM_PLANNER_SPEED/next->nominal_speed);
|
||||
next->recalculate_flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculates the motion plan according to the following algorithm:
|
||||
//
|
||||
// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor)
|
||||
// so that:
|
||||
// a. The junction jerk is within the set limit
|
||||
// b. No speed reduction within one block requires faster deceleration than the one, true constant
|
||||
// acceleration.
|
||||
// 2. Go over every block in chronological order and dial down junction speed reduction values if
|
||||
// a. The speed increase within one block would require faster accelleration than the one, true
|
||||
// constant acceleration.
|
||||
//
|
||||
// When these stages are complete all blocks have an entry_factor that will allow all speed changes to
|
||||
// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than
|
||||
// the set limit. Finally it will:
|
||||
//
|
||||
// 3. Recalculate trapezoids for all blocks.
|
||||
|
||||
void planner_recalculate() {
|
||||
planner_reverse_pass();
|
||||
planner_forward_pass();
|
||||
planner_recalculate_trapezoids();
|
||||
}
|
||||
|
||||
void plan_init() {
|
||||
block_buffer_head = 0;
|
||||
block_buffer_tail = 0;
|
||||
memset(position, 0, sizeof(position)); // clear position
|
||||
previous_speed[0] = 0.0;
|
||||
previous_speed[1] = 0.0;
|
||||
previous_speed[2] = 0.0;
|
||||
previous_speed[3] = 0.0;
|
||||
previous_nominal_speed = 0.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef AUTOTEMP
|
||||
void getHighESpeed()
|
||||
{
|
||||
static float oldt=0;
|
||||
if(!autotemp_enabled){
|
||||
return;
|
||||
}
|
||||
if(degTargetHotend0()+2<autotemp_min) { //probably temperature set to zero.
|
||||
return; //do nothing
|
||||
}
|
||||
|
||||
float high=0.0;
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
|
||||
while(block_index != block_buffer_head) {
|
||||
if((block_buffer[block_index].steps_x != 0) ||
|
||||
(block_buffer[block_index].steps_y != 0) ||
|
||||
(block_buffer[block_index].steps_z != 0)) {
|
||||
float se=(float(block_buffer[block_index].steps_e)/float(block_buffer[block_index].step_event_count))*block_buffer[block_index].nominal_speed;
|
||||
//se; mm/sec;
|
||||
if(se>high)
|
||||
{
|
||||
high=se;
|
||||
}
|
||||
}
|
||||
block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1);
|
||||
}
|
||||
|
||||
float g=autotemp_min+high*autotemp_factor;
|
||||
float t=g;
|
||||
if(t<autotemp_min)
|
||||
t=autotemp_min;
|
||||
if(t>autotemp_max)
|
||||
t=autotemp_max;
|
||||
if(oldt>t)
|
||||
{
|
||||
t=AUTOTEMP_OLDWEIGHT*oldt+(1-AUTOTEMP_OLDWEIGHT)*t;
|
||||
}
|
||||
oldt=t;
|
||||
setTargetHotend0(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
void check_axes_activity() {
|
||||
unsigned char x_active = 0;
|
||||
unsigned char y_active = 0;
|
||||
unsigned char z_active = 0;
|
||||
unsigned char e_active = 0;
|
||||
unsigned char fan_speed = 0;
|
||||
unsigned char tail_fan_speed = 0;
|
||||
block_t *block;
|
||||
|
||||
if(block_buffer_tail != block_buffer_head) {
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
tail_fan_speed = block_buffer[block_index].fan_speed;
|
||||
while(block_index != block_buffer_head) {
|
||||
block = &block_buffer[block_index];
|
||||
if(block->steps_x != 0) x_active++;
|
||||
if(block->steps_y != 0) y_active++;
|
||||
if(block->steps_z != 0) z_active++;
|
||||
if(block->steps_e != 0) e_active++;
|
||||
if(block->fan_speed != 0) fan_speed++;
|
||||
block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if FAN_PIN > -1
|
||||
if (FanSpeed != 0) analogWrite(FAN_PIN,FanSpeed); // If buffer is empty use current fan speed
|
||||
#endif
|
||||
}
|
||||
if((DISABLE_X) && (x_active == 0)) disable_x();
|
||||
if((DISABLE_Y) && (y_active == 0)) disable_y();
|
||||
if((DISABLE_Z) && (z_active == 0)) disable_z();
|
||||
if((DISABLE_E) && (e_active == 0)) { disable_e0();disable_e1();disable_e2(); }
|
||||
#if FAN_PIN > -1
|
||||
if((FanSpeed == 0) && (fan_speed ==0)) analogWrite(FAN_PIN, 0);
|
||||
#endif
|
||||
if (FanSpeed != 0 && tail_fan_speed !=0) {
|
||||
analogWrite(FAN_PIN,tail_fan_speed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float junction_deviation = 0.1;
|
||||
// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in
|
||||
// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
|
||||
// calculation the caller must also provide the physical length of the line in millimeters.
|
||||
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
|
||||
{
|
||||
// Calculate the buffer head after we push this byte
|
||||
int next_buffer_head = next_block_index(block_buffer_head);
|
||||
|
||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||
// Rest here until there is room in the buffer.
|
||||
while(block_buffer_tail == next_buffer_head) {
|
||||
manage_heater();
|
||||
manage_inactivity(1);
|
||||
LCD_STATUS;
|
||||
LED_STATUS;
|
||||
}
|
||||
|
||||
// The target position of the tool in absolute steps
|
||||
// Calculate target position in absolute steps
|
||||
//this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
|
||||
long target[4];
|
||||
target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
|
||||
target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
|
||||
target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
|
||||
target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
|
||||
|
||||
#ifdef PREVENT_DANGEROUS_EXTRUDE
|
||||
if(target[E_AXIS]!=position[E_AXIS])
|
||||
if(degHotend(active_extruder)<EXTRUDE_MINTEMP && !allow_cold_extrude)
|
||||
{
|
||||
position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
|
||||
}
|
||||
if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
|
||||
{
|
||||
position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prepare to set up new block
|
||||
block_t *block = &block_buffer[block_buffer_head];
|
||||
|
||||
// Mark block as not busy (Not executed by the stepper interrupt)
|
||||
block->busy = false;
|
||||
|
||||
// Number of steps for each axis
|
||||
block->steps_x = labs(target[X_AXIS]-position[X_AXIS]);
|
||||
block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);
|
||||
block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
|
||||
block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
|
||||
block->steps_e *= extrudemultiply;
|
||||
block->steps_e /= 100;
|
||||
block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e)));
|
||||
|
||||
// Bail if this is a zero-length block
|
||||
if (block->step_event_count <= dropsegments) { return; };
|
||||
|
||||
block->fan_speed = FanSpeed;
|
||||
|
||||
// Compute direction bits for this block
|
||||
block->direction_bits = 0;
|
||||
if (target[X_AXIS] < position[X_AXIS]) { block->direction_bits |= (1<<X_AXIS); }
|
||||
if (target[Y_AXIS] < position[Y_AXIS]) { block->direction_bits |= (1<<Y_AXIS); }
|
||||
if (target[Z_AXIS] < position[Z_AXIS]) { block->direction_bits |= (1<<Z_AXIS); }
|
||||
if (target[E_AXIS] < position[E_AXIS]) { block->direction_bits |= (1<<E_AXIS); }
|
||||
|
||||
block->active_extruder = extruder;
|
||||
|
||||
//enable active axes
|
||||
if(block->steps_x != 0) enable_x();
|
||||
if(block->steps_y != 0) enable_y();
|
||||
#ifndef Z_LATE_ENABLE
|
||||
if(block->steps_z != 0) enable_z();
|
||||
#endif
|
||||
|
||||
// Enable all
|
||||
if(block->steps_e != 0) { enable_e0();enable_e1();enable_e2(); }
|
||||
|
||||
if (block->steps_e == 0) {
|
||||
if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
|
||||
}
|
||||
else {
|
||||
if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
|
||||
}
|
||||
|
||||
float delta_mm[4];
|
||||
delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
|
||||
delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
|
||||
delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS];
|
||||
delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*extrudemultiply/100.0;
|
||||
// if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments ) {
|
||||
// block->millimeters = abs(delta_mm[E_AXIS]);
|
||||
// } else {
|
||||
// block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));
|
||||
// }
|
||||
|
||||
// TODO - JMG - SORT OUT RETRACTS WHEN e IS NOT ALONE
|
||||
block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) +
|
||||
square(delta_mm[Z_AXIS]) + square(delta_mm[E_AXIS]));
|
||||
float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides
|
||||
|
||||
// Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
|
||||
float inverse_second = feed_rate * inverse_millimeters;
|
||||
|
||||
int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);
|
||||
|
||||
// slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill
|
||||
#ifdef OLD_SLOWDOWN
|
||||
if(moves_queued < (BLOCK_BUFFER_SIZE * 0.5) && moves_queued > 1) feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5);
|
||||
#endif
|
||||
|
||||
#ifdef SLOWDOWN
|
||||
// segment time im micro seconds
|
||||
unsigned long segment_time = lround(1000000.0/inverse_second);
|
||||
if ((moves_queued > 1) && (moves_queued < (BLOCK_BUFFER_SIZE * 0.5))) {
|
||||
if (segment_time < minsegmenttime) { // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more.
|
||||
inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// END OF SLOW DOWN SECTION
|
||||
|
||||
|
||||
block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
|
||||
block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0
|
||||
|
||||
// Calculate and limit speed in mm/sec for each axis
|
||||
float current_speed[4];
|
||||
float speed_factor = 1.0; //factor <=1 do decrease speed
|
||||
for(int i=0; i < 4; i++) {
|
||||
current_speed[i] = delta_mm[i] * inverse_second;
|
||||
if(fabs(current_speed[i]) > max_feedrate[i])
|
||||
speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i]));
|
||||
}
|
||||
|
||||
// Max segement time in us.
|
||||
#ifdef XY_FREQUENCY_LIMIT
|
||||
#define MAX_FREQ_TIME (1000000.0/XY_FREQUENCY_LIMIT)
|
||||
|
||||
// Check and limit the xy direction change frequency
|
||||
unsigned char direction_change = block->direction_bits ^ old_direction_bits;
|
||||
old_direction_bits = block->direction_bits;
|
||||
|
||||
if((direction_change & (1<<X_AXIS)) == 0) {
|
||||
x_segment_time[0] += segment_time;
|
||||
}
|
||||
else {
|
||||
x_segment_time[2] = x_segment_time[1];
|
||||
x_segment_time[1] = x_segment_time[0];
|
||||
x_segment_time[0] = segment_time;
|
||||
}
|
||||
if((direction_change & (1<<Y_AXIS)) == 0) {
|
||||
y_segment_time[0] += segment_time;
|
||||
}
|
||||
else {
|
||||
y_segment_time[2] = y_segment_time[1];
|
||||
y_segment_time[1] = y_segment_time[0];
|
||||
y_segment_time[0] = segment_time;
|
||||
}
|
||||
long max_x_segment_time = max(x_segment_time[0], max(x_segment_time[1], x_segment_time[2]));
|
||||
long max_y_segment_time = max(y_segment_time[0], max(y_segment_time[1], y_segment_time[2]));
|
||||
long min_xy_segment_time =min(max_x_segment_time, max_y_segment_time);
|
||||
if(min_xy_segment_time < MAX_FREQ_TIME) speed_factor = min(speed_factor, speed_factor * (float)min_xy_segment_time / (float)MAX_FREQ_TIME);
|
||||
#endif
|
||||
|
||||
// Correct the speed
|
||||
if( speed_factor < 1.0) {
|
||||
for(unsigned char i=0; i < 4; i++) {
|
||||
current_speed[i] *= speed_factor;
|
||||
}
|
||||
block->nominal_speed *= speed_factor;
|
||||
block->nominal_rate *= speed_factor;
|
||||
}
|
||||
|
||||
// Compute and limit the acceleration rate for the trapezoid generator.
|
||||
float steps_per_mm = block->step_event_count/block->millimeters;
|
||||
if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) {
|
||||
block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
|
||||
}
|
||||
else {
|
||||
block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
|
||||
// Limit acceleration per axis
|
||||
if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS])
|
||||
block->acceleration_st = axis_steps_per_sqr_second[X_AXIS];
|
||||
if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS])
|
||||
block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS];
|
||||
if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS])
|
||||
block->acceleration_st = axis_steps_per_sqr_second[E_AXIS];
|
||||
if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
|
||||
block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
|
||||
}
|
||||
block->acceleration = block->acceleration_st / steps_per_mm;
|
||||
block->acceleration_rate = (long)((float)block->acceleration_st * 8.388608);
|
||||
|
||||
#if 0 // Use old jerk for now
|
||||
// Compute path unit vector
|
||||
double unit_vec[3];
|
||||
|
||||
unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
|
||||
unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
|
||||
unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
|
||||
|
||||
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
|
||||
// Let a circle be tangent to both previous and current path line segments, where the junction
|
||||
// deviation is defined as the distance from the junction to the closest edge of the circle,
|
||||
// colinear with the circle center. The circular segment joining the two paths represents the
|
||||
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
|
||||
// radius of the circle, defined indirectly by junction deviation. This may be also viewed as
|
||||
// path width or max_jerk in the previous grbl version. This approach does not actually deviate
|
||||
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
|
||||
// nonlinearities of both the junction angle and junction velocity.
|
||||
double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
|
||||
|
||||
// Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
|
||||
if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
|
||||
// Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
|
||||
// NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
|
||||
double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
|
||||
- previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
|
||||
- previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
|
||||
|
||||
// Skip and use default max junction speed for 0 degree acute junction.
|
||||
if (cos_theta < 0.95) {
|
||||
vmax_junction = min(previous_nominal_speed,block->nominal_speed);
|
||||
// Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
|
||||
if (cos_theta > -0.95) {
|
||||
// Compute maximum junction velocity based on maximum acceleration and junction deviation
|
||||
double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
|
||||
vmax_junction = min(vmax_junction,
|
||||
sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Start with a safe speed
|
||||
float vmax_junction = max_xy_jerk/2;
|
||||
if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2)
|
||||
vmax_junction = max_z_jerk/2;
|
||||
vmax_junction = min(vmax_junction, block->nominal_speed);
|
||||
if(fabs(current_speed[E_AXIS]) > max_e_jerk/2)
|
||||
vmax_junction = min(vmax_junction, max_e_jerk/2);
|
||||
|
||||
if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
|
||||
float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2));
|
||||
if((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
|
||||
vmax_junction = block->nominal_speed;
|
||||
}
|
||||
if (jerk > max_xy_jerk) {
|
||||
vmax_junction *= (max_xy_jerk/jerk);
|
||||
}
|
||||
if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) > max_z_jerk) {
|
||||
vmax_junction *= (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]));
|
||||
}
|
||||
if(fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]) > max_e_jerk) {
|
||||
vmax_junction *= (max_e_jerk/fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]));
|
||||
}
|
||||
}
|
||||
block->max_entry_speed = vmax_junction;
|
||||
|
||||
// Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
|
||||
double v_allowable = max_allowable_speed(-block->acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
|
||||
block->entry_speed = min(vmax_junction, v_allowable);
|
||||
|
||||
// Initialize planner efficiency flags
|
||||
// Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
|
||||
// If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
|
||||
// the current block and next block junction speeds are guaranteed to always be at their maximum
|
||||
// junction speeds in deceleration and acceleration, respectively. This is due to how the current
|
||||
// block nominal speed limits both the current and next maximum junction speeds. Hence, in both
|
||||
// the reverse and forward planners, the corresponding block junction speed will always be at the
|
||||
// the maximum junction speed and may always be ignored for any speed reduction checks.
|
||||
if (block->nominal_speed <= v_allowable) { block->nominal_length_flag = true; }
|
||||
else { block->nominal_length_flag = false; }
|
||||
block->recalculate_flag = true; // Always calculate trapezoid for new block
|
||||
|
||||
// Update previous path unit_vector and nominal speed
|
||||
memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
|
||||
previous_nominal_speed = block->nominal_speed;
|
||||
|
||||
|
||||
#ifdef ADVANCE
|
||||
// Calculate advance rate
|
||||
if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
|
||||
block->advance_rate = 0;
|
||||
block->advance = 0;
|
||||
}
|
||||
else {
|
||||
long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
|
||||
float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) *
|
||||
(current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUTION_AREA * EXTRUTION_AREA)*256;
|
||||
block->advance = advance;
|
||||
if(acc_dist == 0) {
|
||||
block->advance_rate = 0;
|
||||
}
|
||||
else {
|
||||
block->advance_rate = advance / (float)acc_dist;
|
||||
}
|
||||
}
|
||||
/*
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPGM("advance :");
|
||||
SERIAL_ECHO(block->advance/256.0);
|
||||
SERIAL_ECHOPGM("advance rate :");
|
||||
SERIAL_ECHOLN(block->advance_rate/256.0);
|
||||
*/
|
||||
#endif // ADVANCE
|
||||
|
||||
calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed,
|
||||
MINIMUM_PLANNER_SPEED/block->nominal_speed);
|
||||
|
||||
// Move buffer head
|
||||
block_buffer_head = next_buffer_head;
|
||||
|
||||
// Update position
|
||||
memcpy(position, target, sizeof(target)); // position[] = target[]
|
||||
|
||||
planner_recalculate();
|
||||
|
||||
st_wake_up();
|
||||
}
|
||||
|
||||
void plan_set_position(const float &x, const float &y, const float &z, const float &e)
|
||||
{
|
||||
position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
|
||||
position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
|
||||
position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
|
||||
position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
|
||||
st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
|
||||
previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
|
||||
previous_speed[0] = 0.0;
|
||||
previous_speed[1] = 0.0;
|
||||
previous_speed[2] = 0.0;
|
||||
previous_speed[3] = 0.0;
|
||||
}
|
||||
|
||||
void plan_set_e_position(const float &e)
|
||||
{
|
||||
position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
|
||||
st_set_e_position(position[E_AXIS]);
|
||||
}
|
||||
|
||||
uint8_t movesplanned()
|
||||
{
|
||||
return (block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);
|
||||
}
|
||||
|
||||
void allow_cold_extrudes(bool allow)
|
||||
{
|
||||
#ifdef PREVENT_DANGEROUS_EXTRUDE
|
||||
allow_cold_extrude=allow;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
planner.h - buffers movement commands and manages the acceleration profile plan
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This module is to be considered a sub-module of stepper.c. Please don't include
|
||||
// this file from any other module.
|
||||
|
||||
#ifndef planner_h
|
||||
#define planner_h
|
||||
|
||||
#include "Marlin.h"
|
||||
|
||||
// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in
|
||||
// the source g-code and may never actually be reached if acceleration management is active.
|
||||
typedef struct {
|
||||
// Fields used by the bresenham algorithm for tracing the line
|
||||
long steps_x, steps_y, steps_z, steps_e; // Step count along each axis
|
||||
unsigned long step_event_count; // The number of step events required to complete this block
|
||||
long accelerate_until; // The index of the step event on which to stop acceleration
|
||||
long decelerate_after; // The index of the step event on which to start decelerating
|
||||
long acceleration_rate; // The acceleration rate used for acceleration calculation
|
||||
unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
|
||||
unsigned char active_extruder; // Selects the active extruder
|
||||
#ifdef ADVANCE
|
||||
long advance_rate;
|
||||
volatile long initial_advance;
|
||||
volatile long final_advance;
|
||||
float advance;
|
||||
#endif
|
||||
|
||||
// Fields used by the motion planner to manage acceleration
|
||||
// float speed_x, speed_y, speed_z, speed_e; // Nominal mm/sec for each axis
|
||||
float nominal_speed; // The nominal speed for this block in mm/sec
|
||||
float entry_speed; // Entry speed at previous-current junction in mm/sec
|
||||
float max_entry_speed; // Maximum allowable junction entry speed in mm/sec
|
||||
float millimeters; // The total travel of this block in mm
|
||||
float acceleration; // acceleration mm/sec^2
|
||||
unsigned char recalculate_flag; // Planner flag to recalculate trapezoids on entry junction
|
||||
unsigned char nominal_length_flag; // Planner flag for nominal speed always reached
|
||||
|
||||
// Settings for the trapezoid generator
|
||||
unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec
|
||||
unsigned long initial_rate; // The jerk-adjusted step rate at start of block
|
||||
unsigned long final_rate; // The minimal rate at exit
|
||||
unsigned long acceleration_st; // acceleration steps/sec^2
|
||||
unsigned long fan_speed;
|
||||
volatile char busy;
|
||||
} block_t;
|
||||
|
||||
// Initialize the motion plan subsystem
|
||||
void plan_init();
|
||||
|
||||
// Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in
|
||||
// millimaters. Feed rate specifies the speed of the motion.
|
||||
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder);
|
||||
|
||||
// Set position. Used for G92 instructions.
|
||||
void plan_set_position(const float &x, const float &y, const float &z, const float &e);
|
||||
void plan_set_e_position(const float &e);
|
||||
|
||||
|
||||
|
||||
void check_axes_activity();
|
||||
uint8_t movesplanned(); //return the nr of buffered moves
|
||||
|
||||
extern unsigned long minsegmenttime;
|
||||
extern float max_feedrate[4]; // set the max speeds
|
||||
extern float axis_steps_per_unit[4];
|
||||
extern unsigned long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software
|
||||
extern float minimumfeedrate;
|
||||
extern float acceleration; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
|
||||
extern float retract_acceleration; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
|
||||
extern float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
|
||||
extern float max_z_jerk;
|
||||
extern float max_e_jerk;
|
||||
extern float mintravelfeedrate;
|
||||
extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
|
||||
|
||||
#ifdef AUTOTEMP
|
||||
extern bool autotemp_enabled;
|
||||
extern float autotemp_max;
|
||||
extern float autotemp_min;
|
||||
extern float autotemp_factor;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
extern block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
|
||||
extern volatile unsigned char block_buffer_head; // Index of the next block to be pushed
|
||||
extern volatile unsigned char block_buffer_tail;
|
||||
// Called when the current block is no longer needed. Discards the block and makes the memory
|
||||
// availible for new blocks.
|
||||
FORCE_INLINE void plan_discard_current_block()
|
||||
{
|
||||
if (block_buffer_head != block_buffer_tail) {
|
||||
block_buffer_tail = (block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the current block. Returns NULL if buffer empty
|
||||
FORCE_INLINE block_t *plan_get_current_block()
|
||||
{
|
||||
if (block_buffer_head == block_buffer_tail) {
|
||||
return(NULL);
|
||||
}
|
||||
block_t *block = &block_buffer[block_buffer_tail];
|
||||
block->busy = true;
|
||||
return(block);
|
||||
}
|
||||
|
||||
// Gets the current block. Returns NULL if buffer empty
|
||||
FORCE_INLINE bool blocks_queued()
|
||||
{
|
||||
if (block_buffer_head == block_buffer_tail) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void allow_cold_extrudes(bool allow);
|
||||
#endif
|
||||
@@ -1,9 +1,11 @@
|
||||
#ifndef SPEED_LOOKUPTABLE_H
|
||||
#define SPEED_LOOKUPTABLE_H
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Marlin.h"
|
||||
|
||||
uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
|
||||
#if F_CPU == 16000000
|
||||
|
||||
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\
|
||||
{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135},
|
||||
{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32},
|
||||
{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14},
|
||||
@@ -35,9 +37,10 @@ uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
|
||||
{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0},
|
||||
{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0},
|
||||
{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0},
|
||||
{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0},
|
||||
{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}
|
||||
};
|
||||
uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
|
||||
|
||||
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\
|
||||
{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894},
|
||||
{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657},
|
||||
{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331},
|
||||
@@ -69,7 +72,81 @@ uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
|
||||
{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4},
|
||||
{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4},
|
||||
{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4},
|
||||
{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3},
|
||||
{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
|
||||
{62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167},
|
||||
{1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40},
|
||||
{604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17},
|
||||
{404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10},
|
||||
{303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6},
|
||||
{243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5},
|
||||
{202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4},
|
||||
{173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2},
|
||||
{152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2},
|
||||
{135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2},
|
||||
{121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2},
|
||||
{110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1},
|
||||
{101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1},
|
||||
{93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0},
|
||||
{87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0},
|
||||
{81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0},
|
||||
{76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1},
|
||||
{71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1},
|
||||
{67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0},
|
||||
{64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1},
|
||||
{60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0},
|
||||
{58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0},
|
||||
{55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0},
|
||||
{53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1},
|
||||
{50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1},
|
||||
{48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1},
|
||||
{46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0},
|
||||
{45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0},
|
||||
{43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0},
|
||||
{42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0},
|
||||
{40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0},
|
||||
{39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0},
|
||||
};
|
||||
|
||||
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
|
||||
{62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003},
|
||||
{24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745},
|
||||
{14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385},
|
||||
{10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235},
|
||||
{8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158},
|
||||
{6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113},
|
||||
{5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86},
|
||||
{5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67},
|
||||
{4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53},
|
||||
{4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44},
|
||||
{3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36},
|
||||
{3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31},
|
||||
{3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27},
|
||||
{2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23},
|
||||
{2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20},
|
||||
{2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18},
|
||||
{2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16},
|
||||
{2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14},
|
||||
{2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13},
|
||||
{1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12},
|
||||
{1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10},
|
||||
{1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10},
|
||||
{1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9},
|
||||
{1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8},
|
||||
{1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7},
|
||||
{1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7},
|
||||
{1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6},
|
||||
{1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6},
|
||||
{1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6},
|
||||
{1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5},
|
||||
{1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5},
|
||||
{1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5},
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,850 @@
|
||||
/*
|
||||
stepper.c - stepper motor driver: executes motion plans using stepper motors
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
|
||||
and Philipp Tiefenbacher. */
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "stepper.h"
|
||||
#include "planner.h"
|
||||
#include "temperature.h"
|
||||
#include "ultralcd.h"
|
||||
#include "language.h"
|
||||
#include "led.h"
|
||||
#include "speed_lookuptable.h"
|
||||
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//=============================public variables ============================
|
||||
//===========================================================================
|
||||
block_t *current_block; // A pointer to the block currently being traced
|
||||
volatile bool endstop_z_hit=false;
|
||||
bool old_z_min_endstop=false;
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//=============================private variables ============================
|
||||
//===========================================================================
|
||||
//static makes it inpossible to be called from outside of this file by extern.!
|
||||
|
||||
// Variables used by The Stepper Driver Interrupt
|
||||
static unsigned char out_bits; // The next stepping-bits to be output
|
||||
static long counter_x, // Counter variables for the bresenham line tracer
|
||||
counter_y,
|
||||
counter_z,
|
||||
counter_e;
|
||||
volatile static unsigned long step_events_completed; // The number of step events executed in the current block
|
||||
#ifdef ADVANCE
|
||||
static long advance_rate, advance, final_advance = 0;
|
||||
static long old_advance = 0;
|
||||
#endif
|
||||
static long e_steps[3];
|
||||
static long acceleration_time, deceleration_time;
|
||||
//static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
|
||||
static unsigned short acc_step_rate; // needed for deccelaration start point
|
||||
static char step_loops;
|
||||
static unsigned short OCR1A_nominal;
|
||||
|
||||
volatile long endstops_trigsteps[3]={0,0,0};
|
||||
volatile long endstops_stepsTotal,endstops_stepsDone;
|
||||
static volatile bool endstop_x_hit=false;
|
||||
static volatile bool endstop_y_hit=false;
|
||||
|
||||
static bool old_x_min_endstop=false;
|
||||
static bool old_x_max_endstop=false;
|
||||
static bool old_y_min_endstop=false;
|
||||
static bool old_y_max_endstop=false;
|
||||
static bool old_z_max_endstop=false;
|
||||
|
||||
static bool check_endstops = true;
|
||||
|
||||
volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
|
||||
volatile char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
|
||||
|
||||
//===========================================================================
|
||||
//=============================functions ============================
|
||||
//===========================================================================
|
||||
|
||||
#define CHECK_ENDSTOPS if(check_endstops)
|
||||
|
||||
// intRes = intIn1 * intIn2 >> 16
|
||||
// uses:
|
||||
// r26 to store 0
|
||||
// r27 to store the byte 1 of the 24 bit result
|
||||
#define MultiU16X8toH16(intRes, charIn1, intIn2) \
|
||||
asm volatile ( \
|
||||
"clr r26 \n\t" \
|
||||
"mul %A1, %B2 \n\t" \
|
||||
"movw %A0, r0 \n\t" \
|
||||
"mul %A1, %A2 \n\t" \
|
||||
"add %A0, r1 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"lsr r0 \n\t" \
|
||||
"adc %A0, r26 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"clr r1 \n\t" \
|
||||
: \
|
||||
"=&r" (intRes) \
|
||||
: \
|
||||
"d" (charIn1), \
|
||||
"d" (intIn2) \
|
||||
: \
|
||||
"r26" \
|
||||
)
|
||||
|
||||
// intRes = longIn1 * longIn2 >> 24
|
||||
// uses:
|
||||
// r26 to store 0
|
||||
// r27 to store the byte 1 of the 48bit result
|
||||
#define MultiU24X24toH16(intRes, longIn1, longIn2) \
|
||||
asm volatile ( \
|
||||
"clr r26 \n\t" \
|
||||
"mul %A1, %B2 \n\t" \
|
||||
"mov r27, r1 \n\t" \
|
||||
"mul %B1, %C2 \n\t" \
|
||||
"movw %A0, r0 \n\t" \
|
||||
"mul %C1, %C2 \n\t" \
|
||||
"add %B0, r0 \n\t" \
|
||||
"mul %C1, %B2 \n\t" \
|
||||
"add %A0, r0 \n\t" \
|
||||
"adc %B0, r1 \n\t" \
|
||||
"mul %A1, %C2 \n\t" \
|
||||
"add r27, r0 \n\t" \
|
||||
"adc %A0, r1 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"mul %B1, %B2 \n\t" \
|
||||
"add r27, r0 \n\t" \
|
||||
"adc %A0, r1 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"mul %C1, %A2 \n\t" \
|
||||
"add r27, r0 \n\t" \
|
||||
"adc %A0, r1 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"mul %B1, %A2 \n\t" \
|
||||
"add r27, r1 \n\t" \
|
||||
"adc %A0, r26 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"lsr r27 \n\t" \
|
||||
"adc %A0, r26 \n\t" \
|
||||
"adc %B0, r26 \n\t" \
|
||||
"clr r1 \n\t" \
|
||||
: \
|
||||
"=&r" (intRes) \
|
||||
: \
|
||||
"d" (longIn1), \
|
||||
"d" (longIn2) \
|
||||
: \
|
||||
"r26" , "r27" \
|
||||
)
|
||||
|
||||
// Some useful constants
|
||||
|
||||
#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<<OCIE1A)
|
||||
#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A)
|
||||
|
||||
|
||||
void checkHitEndstops()
|
||||
{
|
||||
if( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
|
||||
SERIAL_ECHO_START;
|
||||
SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
|
||||
if(endstop_x_hit) {
|
||||
SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
|
||||
}
|
||||
if(endstop_y_hit) {
|
||||
SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
|
||||
}
|
||||
if(endstop_z_hit) {
|
||||
SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
|
||||
}
|
||||
SERIAL_ECHOLN("");
|
||||
endstop_x_hit=false;
|
||||
endstop_y_hit=false;
|
||||
endstop_z_hit=false;
|
||||
}
|
||||
}
|
||||
|
||||
void endstops_hit_on_purpose()
|
||||
{
|
||||
endstop_x_hit=false;
|
||||
endstop_y_hit=false;
|
||||
endstop_z_hit=false;
|
||||
}
|
||||
|
||||
void enable_endstops(bool check)
|
||||
{
|
||||
check_endstops = check;
|
||||
}
|
||||
|
||||
// __________________________
|
||||
// /| |\ _________________ ^
|
||||
// / | | \ /| |\ |
|
||||
// / | | \ / | | \ s
|
||||
// / | | | | | \ p
|
||||
// / | | | | | \ e
|
||||
// +-----+------------------------+---+--+---------------+----+ e
|
||||
// | BLOCK 1 | BLOCK 2 | d
|
||||
//
|
||||
// time ----->
|
||||
//
|
||||
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
|
||||
// first block->accelerate_until step_events_completed, then keeps going at constant speed until
|
||||
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
|
||||
// The slope of acceleration is calculated with the leib ramp alghorithm.
|
||||
|
||||
void st_wake_up() {
|
||||
// TCNT1 = 0;
|
||||
ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
}
|
||||
|
||||
FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
|
||||
unsigned short timer;
|
||||
if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
|
||||
|
||||
if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
|
||||
step_rate = (step_rate >> 2)&0x3fff;
|
||||
step_loops = 4;
|
||||
}
|
||||
else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times
|
||||
step_rate = (step_rate >> 1)&0x7fff;
|
||||
step_loops = 2;
|
||||
}
|
||||
else {
|
||||
step_loops = 1;
|
||||
}
|
||||
|
||||
if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
|
||||
step_rate -= (F_CPU/500000); // Correct for minimal speed
|
||||
if(step_rate >= (8*256)){ // higher step rate
|
||||
unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
|
||||
unsigned char tmp_step_rate = (step_rate & 0x00ff);
|
||||
unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
|
||||
MultiU16X8toH16(timer, tmp_step_rate, gain);
|
||||
timer = (unsigned short)pgm_read_word_near(table_address) - timer;
|
||||
}
|
||||
else { // lower step rates
|
||||
unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
|
||||
table_address += ((step_rate)>>1) & 0xfffc;
|
||||
timer = (unsigned short)pgm_read_word_near(table_address);
|
||||
timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
|
||||
}
|
||||
if(timer < 100) { timer = 100; MYSERIAL.print(MSG_STEPPER_TO_HIGH); MYSERIAL.println(step_rate); }//(20kHz this should never happen)
|
||||
return timer;
|
||||
}
|
||||
|
||||
// Initializes the trapezoid generator from the current block. Called whenever a new
|
||||
// block begins.
|
||||
FORCE_INLINE void trapezoid_generator_reset() {
|
||||
#ifdef ADVANCE
|
||||
advance = current_block->initial_advance;
|
||||
final_advance = current_block->final_advance;
|
||||
// Do E steps + advance steps
|
||||
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
|
||||
old_advance = advance >>8;
|
||||
#endif
|
||||
deceleration_time = 0;
|
||||
// step_rate to timer interval
|
||||
acc_step_rate = current_block->initial_rate;
|
||||
acceleration_time = calc_timer(acc_step_rate);
|
||||
OCR1A = acceleration_time;
|
||||
OCR1A_nominal = calc_timer(current_block->nominal_rate);
|
||||
|
||||
|
||||
|
||||
// SERIAL_ECHO_START;
|
||||
// SERIAL_ECHOPGM("advance :");
|
||||
// SERIAL_ECHO(current_block->advance/256.0);
|
||||
// SERIAL_ECHOPGM("advance rate :");
|
||||
// SERIAL_ECHO(current_block->advance_rate/256.0);
|
||||
// SERIAL_ECHOPGM("initial advance :");
|
||||
// SERIAL_ECHO(current_block->initial_advance/256.0);
|
||||
// SERIAL_ECHOPGM("final advance :");
|
||||
// SERIAL_ECHOLN(current_block->final_advance/256.0);
|
||||
|
||||
}
|
||||
|
||||
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
|
||||
// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
// If there is no current block, attempt to pop one from the buffer
|
||||
if (current_block == NULL) {
|
||||
// Anything in the buffer?
|
||||
current_block = plan_get_current_block();
|
||||
if (current_block != NULL) {
|
||||
current_block->busy = true;
|
||||
trapezoid_generator_reset();
|
||||
counter_x = -(current_block->step_event_count >> 1);
|
||||
counter_y = counter_x;
|
||||
counter_z = counter_x;
|
||||
counter_e = counter_x;
|
||||
step_events_completed = 0;
|
||||
|
||||
#ifdef Z_LATE_ENABLE
|
||||
if(current_block->steps_z > 0) {
|
||||
enable_z();
|
||||
OCR1A = 2000; //1ms wait
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// #ifdef ADVANCE
|
||||
// e_steps[current_block->active_extruder] = 0;
|
||||
// #endif
|
||||
}
|
||||
else {
|
||||
OCR1A=2000; // 1kHz.
|
||||
}
|
||||
}
|
||||
|
||||
if (current_block != NULL) {
|
||||
// Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt
|
||||
out_bits = current_block->direction_bits;
|
||||
|
||||
// Set direction en check limit switches
|
||||
if ((out_bits & (1<<X_AXIS)) != 0) { // -direction
|
||||
WRITE(X_DIR_PIN, INVERT_X_DIR);
|
||||
count_direction[X_AXIS]=-1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if X_MIN_PIN > -1
|
||||
bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING);
|
||||
if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
|
||||
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
|
||||
endstop_x_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_x_min_endstop = x_min_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else { // +direction
|
||||
WRITE(X_DIR_PIN,!INVERT_X_DIR);
|
||||
count_direction[X_AXIS]=1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if X_MAX_PIN > -1
|
||||
bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING);
|
||||
if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
|
||||
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
|
||||
endstop_x_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_x_max_endstop = x_max_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((out_bits & (1<<Y_AXIS)) != 0) { // -direction
|
||||
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
|
||||
count_direction[Y_AXIS]=-1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if Y_MIN_PIN > -1
|
||||
bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING);
|
||||
if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) {
|
||||
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
|
||||
endstop_y_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_y_min_endstop = y_min_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else { // +direction
|
||||
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
|
||||
count_direction[Y_AXIS]=1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if Y_MAX_PIN > -1
|
||||
bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING);
|
||||
if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){
|
||||
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
|
||||
endstop_y_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_y_max_endstop = y_max_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((out_bits & (1<<Z_AXIS)) != 0) { // -direction
|
||||
WRITE(Z_DIR_PIN,INVERT_Z_DIR);
|
||||
count_direction[Z_AXIS]=-1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if Z_MIN_PIN > -1
|
||||
bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING);
|
||||
if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) {
|
||||
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
|
||||
endstop_z_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_z_min_endstop = z_min_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else { // +direction
|
||||
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
|
||||
count_direction[Z_AXIS]=1;
|
||||
CHECK_ENDSTOPS
|
||||
{
|
||||
#if Z_MAX_PIN > -1
|
||||
bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING);
|
||||
if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) {
|
||||
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
|
||||
endstop_z_hit=true;
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
old_z_max_endstop = z_max_endstop;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ADVANCE
|
||||
if ((out_bits & (1<<E_AXIS)) != 0) { // -direction
|
||||
REV_E_DIR();
|
||||
count_direction[E_AXIS]=-1;
|
||||
}
|
||||
else { // +direction
|
||||
NORM_E_DIR();
|
||||
count_direction[E_AXIS]=1;
|
||||
}
|
||||
#endif //!ADVANCE
|
||||
|
||||
|
||||
|
||||
for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
|
||||
#if MOTHERBOARD != 8 // !teensylu
|
||||
MSerial.checkRx(); // Check for serial chars.
|
||||
#endif
|
||||
|
||||
#ifdef ADVANCE
|
||||
counter_e += current_block->steps_e;
|
||||
if (counter_e > 0) {
|
||||
counter_e -= current_block->step_event_count;
|
||||
if ((out_bits & (1<<E_AXIS)) != 0) { // - direction
|
||||
e_steps[current_block->active_extruder]--;
|
||||
}
|
||||
else {
|
||||
e_steps[current_block->active_extruder]++;
|
||||
}
|
||||
}
|
||||
#endif //ADVANCE
|
||||
|
||||
counter_x += current_block->steps_x;
|
||||
if (counter_x > 0) {
|
||||
WRITE(X_STEP_PIN, HIGH);
|
||||
counter_x -= current_block->step_event_count;
|
||||
WRITE(X_STEP_PIN, LOW);
|
||||
count_position[X_AXIS]+=count_direction[X_AXIS];
|
||||
}
|
||||
|
||||
counter_y += current_block->steps_y;
|
||||
if (counter_y > 0) {
|
||||
WRITE(Y_STEP_PIN, HIGH);
|
||||
counter_y -= current_block->step_event_count;
|
||||
WRITE(Y_STEP_PIN, LOW);
|
||||
count_position[Y_AXIS]+=count_direction[Y_AXIS];
|
||||
}
|
||||
|
||||
counter_z += current_block->steps_z;
|
||||
if (counter_z > 0) {
|
||||
WRITE(Z_STEP_PIN, HIGH);
|
||||
counter_z -= current_block->step_event_count;
|
||||
WRITE(Z_STEP_PIN, LOW);
|
||||
count_position[Z_AXIS]+=count_direction[Z_AXIS];
|
||||
}
|
||||
|
||||
#ifndef ADVANCE
|
||||
counter_e += current_block->steps_e;
|
||||
if (counter_e > 0) {
|
||||
WRITE_E_STEP(HIGH);
|
||||
counter_e -= current_block->step_event_count;
|
||||
WRITE_E_STEP(LOW);
|
||||
count_position[E_AXIS]+=count_direction[E_AXIS];
|
||||
}
|
||||
#endif //!ADVANCE
|
||||
step_events_completed += 1;
|
||||
if(step_events_completed >= current_block->step_event_count) break;
|
||||
}
|
||||
// Calculare new timer value
|
||||
unsigned short timer;
|
||||
unsigned short step_rate;
|
||||
if (step_events_completed <= (unsigned long int)current_block->accelerate_until) {
|
||||
|
||||
MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
|
||||
acc_step_rate += current_block->initial_rate;
|
||||
|
||||
// upper limit
|
||||
if(acc_step_rate > current_block->nominal_rate)
|
||||
acc_step_rate = current_block->nominal_rate;
|
||||
|
||||
// step_rate to timer interval
|
||||
timer = calc_timer(acc_step_rate);
|
||||
OCR1A = timer;
|
||||
acceleration_time += timer;
|
||||
#ifdef ADVANCE
|
||||
for(int8_t i=0; i < step_loops; i++) {
|
||||
advance += advance_rate;
|
||||
}
|
||||
//if(advance > current_block->advance) advance = current_block->advance;
|
||||
// Do E steps + advance steps
|
||||
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
|
||||
old_advance = advance >>8;
|
||||
|
||||
#endif
|
||||
}
|
||||
else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
|
||||
MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
|
||||
|
||||
if(step_rate > acc_step_rate) { // Check step_rate stays positive
|
||||
step_rate = current_block->final_rate;
|
||||
}
|
||||
else {
|
||||
step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point.
|
||||
}
|
||||
|
||||
// lower limit
|
||||
if(step_rate < current_block->final_rate)
|
||||
step_rate = current_block->final_rate;
|
||||
|
||||
// step_rate to timer interval
|
||||
timer = calc_timer(step_rate);
|
||||
OCR1A = timer;
|
||||
deceleration_time += timer;
|
||||
#ifdef ADVANCE
|
||||
for(int8_t i=0; i < step_loops; i++) {
|
||||
advance -= advance_rate;
|
||||
}
|
||||
if(advance < final_advance) advance = final_advance;
|
||||
// Do E steps + advance steps
|
||||
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
|
||||
old_advance = advance >>8;
|
||||
#endif //ADVANCE
|
||||
}
|
||||
else {
|
||||
OCR1A = OCR1A_nominal;
|
||||
}
|
||||
|
||||
// If current block is finished, reset pointer
|
||||
if (step_events_completed >= current_block->step_event_count) {
|
||||
current_block = NULL;
|
||||
plan_discard_current_block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ADVANCE
|
||||
unsigned char old_OCR0A;
|
||||
// Timer interrupt for E. e_steps is set in the main routine;
|
||||
// Timer 0 is shared with millies
|
||||
ISR(TIMER0_COMPA_vect)
|
||||
{
|
||||
old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz)
|
||||
OCR0A = old_OCR0A;
|
||||
// Set E direction (Depends on E direction + advance)
|
||||
for(unsigned char i=0; i<4;i++) {
|
||||
if (e_steps[0] != 0) {
|
||||
WRITE(E0_STEP_PIN, LOW);
|
||||
if (e_steps[0] < 0) {
|
||||
WRITE(E0_DIR_PIN, INVERT_E0_DIR);
|
||||
e_steps[0]++;
|
||||
WRITE(E0_STEP_PIN, HIGH);
|
||||
}
|
||||
else if (e_steps[0] > 0) {
|
||||
WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
|
||||
e_steps[0]--;
|
||||
WRITE(E0_STEP_PIN, HIGH);
|
||||
}
|
||||
}
|
||||
#if EXTRUDERS > 1
|
||||
if (e_steps[1] != 0) {
|
||||
WRITE(E1_STEP_PIN, LOW);
|
||||
if (e_steps[1] < 0) {
|
||||
WRITE(E1_DIR_PIN, INVERT_E1_DIR);
|
||||
e_steps[1]++;
|
||||
WRITE(E1_STEP_PIN, HIGH);
|
||||
}
|
||||
else if (e_steps[1] > 0) {
|
||||
WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
|
||||
e_steps[1]--;
|
||||
WRITE(E1_STEP_PIN, HIGH);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if EXTRUDERS > 2
|
||||
if (e_steps[2] != 0) {
|
||||
WRITE(E2_STEP_PIN, LOW);
|
||||
if (e_steps[2] < 0) {
|
||||
WRITE(E2_DIR_PIN, INVERT_E2_DIR);
|
||||
e_steps[2]++;
|
||||
WRITE(E2_STEP_PIN, HIGH);
|
||||
}
|
||||
else if (e_steps[2] > 0) {
|
||||
WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
|
||||
e_steps[2]--;
|
||||
WRITE(E2_STEP_PIN, HIGH);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // ADVANCE
|
||||
|
||||
void st_init()
|
||||
{
|
||||
//Initialize Dir Pins
|
||||
#if X_DIR_PIN > -1
|
||||
SET_OUTPUT(X_DIR_PIN);
|
||||
#endif
|
||||
#if Y_DIR_PIN > -1
|
||||
SET_OUTPUT(Y_DIR_PIN);
|
||||
#endif
|
||||
#if Z_DIR_PIN > -1
|
||||
SET_OUTPUT(Z_DIR_PIN);
|
||||
#endif
|
||||
#if E0_DIR_PIN > -1
|
||||
SET_OUTPUT(E0_DIR_PIN);
|
||||
#endif
|
||||
#if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1)
|
||||
SET_OUTPUT(E1_DIR_PIN);
|
||||
#endif
|
||||
#if defined(E2_DIR_PIN) && (E2_DIR_PIN > -1)
|
||||
SET_OUTPUT(E2_DIR_PIN);
|
||||
#endif
|
||||
|
||||
//Initialize Enable Pins - steppers default to disabled.
|
||||
|
||||
#if (X_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(X_ENABLE_PIN);
|
||||
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#if (Y_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(Y_ENABLE_PIN);
|
||||
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#if (Z_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(Z_ENABLE_PIN);
|
||||
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#if (E0_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(E0_ENABLE_PIN);
|
||||
if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#if defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(E1_ENABLE_PIN);
|
||||
if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#if defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
|
||||
SET_OUTPUT(E2_ENABLE_PIN);
|
||||
if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
|
||||
//endstops and pullups
|
||||
#ifdef ENDSTOPPULLUPS
|
||||
#if X_MIN_PIN > -1
|
||||
SET_INPUT(X_MIN_PIN);
|
||||
WRITE(X_MIN_PIN,HIGH);
|
||||
#endif
|
||||
#if X_MAX_PIN > -1
|
||||
SET_INPUT(X_MAX_PIN);
|
||||
WRITE(X_MAX_PIN,HIGH);
|
||||
#endif
|
||||
#if Y_MIN_PIN > -1
|
||||
SET_INPUT(Y_MIN_PIN);
|
||||
WRITE(Y_MIN_PIN,HIGH);
|
||||
#endif
|
||||
#if Y_MAX_PIN > -1
|
||||
SET_INPUT(Y_MAX_PIN);
|
||||
WRITE(Y_MAX_PIN,HIGH);
|
||||
#endif
|
||||
#if Z_MIN_PIN > -1
|
||||
SET_INPUT(Z_MIN_PIN);
|
||||
WRITE(Z_MIN_PIN,HIGH);
|
||||
#endif
|
||||
#if Z_MAX_PIN > -1
|
||||
SET_INPUT(Z_MAX_PIN);
|
||||
WRITE(Z_MAX_PIN,HIGH);
|
||||
#endif
|
||||
#else //ENDSTOPPULLUPS
|
||||
#if X_MIN_PIN > -1
|
||||
SET_INPUT(X_MIN_PIN);
|
||||
#endif
|
||||
#if X_MAX_PIN > -1
|
||||
SET_INPUT(X_MAX_PIN);
|
||||
#endif
|
||||
#if Y_MIN_PIN > -1
|
||||
SET_INPUT(Y_MIN_PIN);
|
||||
#endif
|
||||
#if Y_MAX_PIN > -1
|
||||
SET_INPUT(Y_MAX_PIN);
|
||||
#endif
|
||||
#if Z_MIN_PIN > -1
|
||||
SET_INPUT(Z_MIN_PIN);
|
||||
#endif
|
||||
#if Z_MAX_PIN > -1
|
||||
SET_INPUT(Z_MAX_PIN);
|
||||
#endif
|
||||
#endif //ENDSTOPPULLUPS
|
||||
|
||||
|
||||
//Initialize Step Pins
|
||||
#if (X_STEP_PIN > -1)
|
||||
SET_OUTPUT(X_STEP_PIN);
|
||||
#if X_ENABLE_PIN > -1
|
||||
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
#if (Y_STEP_PIN > -1)
|
||||
SET_OUTPUT(Y_STEP_PIN);
|
||||
#if Y_ENABLE_PIN > -1
|
||||
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
#if (Z_STEP_PIN > -1)
|
||||
SET_OUTPUT(Z_STEP_PIN);
|
||||
#if Z_ENABLE_PIN > -1
|
||||
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
#if (E0_STEP_PIN > -1)
|
||||
SET_OUTPUT(E0_STEP_PIN);
|
||||
#if E0_ENABLE_PIN > -1
|
||||
if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
#if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1)
|
||||
SET_OUTPUT(E1_STEP_PIN);
|
||||
#if E1_ENABLE_PIN > -1
|
||||
if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
#if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1)
|
||||
SET_OUTPUT(E2_STEP_PIN);
|
||||
#if E2_ENABLE_PIN > -1
|
||||
if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,HIGH);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONTROLLERFAN_PIN
|
||||
SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
|
||||
#endif
|
||||
|
||||
// waveform generation = 0100 = CTC
|
||||
TCCR1B &= ~(1<<WGM13);
|
||||
TCCR1B |= (1<<WGM12);
|
||||
TCCR1A &= ~(1<<WGM11);
|
||||
TCCR1A &= ~(1<<WGM10);
|
||||
|
||||
// output mode = 00 (disconnected)
|
||||
TCCR1A &= ~(3<<COM1A0);
|
||||
TCCR1A &= ~(3<<COM1B0);
|
||||
|
||||
// Set the timer pre-scaler
|
||||
// Generally we use a divider of 8, resulting in a 2MHz timer
|
||||
// frequency on a 16MHz MCU. If you are going to change this, be
|
||||
// sure to regenerate speed_lookuptable.h with
|
||||
// create_speed_lookuptable.py
|
||||
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (2<<CS10);
|
||||
|
||||
OCR1A = 0x4000;
|
||||
TCNT1 = 0;
|
||||
ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
|
||||
#ifdef ADVANCE
|
||||
#if defined(TCCR0A) && defined(WGM01)
|
||||
TCCR0A &= ~(1<<WGM01);
|
||||
TCCR0A &= ~(1<<WGM00);
|
||||
#endif
|
||||
e_steps[0] = 0;
|
||||
e_steps[1] = 0;
|
||||
e_steps[2] = 0;
|
||||
TIMSK0 |= (1<<OCIE0A);
|
||||
#endif //ADVANCE
|
||||
|
||||
#ifdef ENDSTOPS_ONLY_FOR_HOMING
|
||||
enable_endstops(false);
|
||||
#else
|
||||
enable_endstops(true);
|
||||
#endif
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
|
||||
// Block until all buffered steps are executed
|
||||
void st_synchronize()
|
||||
{
|
||||
while( blocks_queued()) {
|
||||
manage_heater();
|
||||
manage_inactivity(1);
|
||||
LCD_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
void st_set_position(const long &x, const long &y, const long &z, const long &e)
|
||||
{
|
||||
CRITICAL_SECTION_START;
|
||||
count_position[X_AXIS] = x;
|
||||
count_position[Y_AXIS] = y;
|
||||
count_position[Z_AXIS] = z;
|
||||
count_position[E_AXIS] = e;
|
||||
CRITICAL_SECTION_END;
|
||||
}
|
||||
|
||||
void st_set_e_position(const long &e)
|
||||
{
|
||||
CRITICAL_SECTION_START;
|
||||
count_position[E_AXIS] = e;
|
||||
CRITICAL_SECTION_END;
|
||||
}
|
||||
|
||||
long st_get_position(uint8_t axis)
|
||||
{
|
||||
long count_pos;
|
||||
CRITICAL_SECTION_START;
|
||||
count_pos = count_position[axis];
|
||||
CRITICAL_SECTION_END;
|
||||
return count_pos;
|
||||
}
|
||||
|
||||
void finishAndDisableSteppers()
|
||||
{
|
||||
st_synchronize();
|
||||
LCD_MESSAGEPGM(MSG_STEPPER_RELEASED);
|
||||
disable_x();
|
||||
disable_y();
|
||||
disable_z();
|
||||
disable_e0();
|
||||
disable_e1();
|
||||
disable_e2();
|
||||
}
|
||||
|
||||
void quickStop()
|
||||
{
|
||||
DISABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
while(blocks_queued())
|
||||
plan_discard_current_block();
|
||||
current_block = NULL;
|
||||
ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef stepper_h
|
||||
#define stepper_h
|
||||
|
||||
#include "planner.h"
|
||||
|
||||
#if EXTRUDERS > 2
|
||||
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 2) { WRITE(E2_STEP_PIN, v); } else { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}}
|
||||
#define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(!E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(!E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}}
|
||||
#define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}}
|
||||
#elif EXTRUDERS > 1
|
||||
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
|
||||
#define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
|
||||
#define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
|
||||
#else
|
||||
#define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
|
||||
#define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
|
||||
#define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR)
|
||||
#endif
|
||||
|
||||
|
||||
// Initialize and start the stepper motor subsystem
|
||||
void st_init();
|
||||
|
||||
// Block until all buffered steps are executed
|
||||
void st_synchronize();
|
||||
|
||||
// Set current position in steps
|
||||
void st_set_position(const long &x, const long &y, const long &z, const long &e);
|
||||
void st_set_e_position(const long &e);
|
||||
|
||||
// Get current position in steps
|
||||
long st_get_position(uint8_t axis);
|
||||
|
||||
// The stepper subsystem goes to sleep when it runs out of things to execute. Call this
|
||||
// to notify the subsystem that it is time to go to work.
|
||||
void st_wake_up();
|
||||
|
||||
|
||||
void checkHitEndstops(); //call from somwhere to create an serial error message with the locations the endstops where hit, in case they were triggered
|
||||
void endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homeing and before a routine call of checkHitEndstops();
|
||||
|
||||
void enable_endstops(bool check); // Enable/disable endstop checking
|
||||
|
||||
void checkStepperErrors(); //Print errors detected by the stepper
|
||||
|
||||
void finishAndDisableSteppers();
|
||||
|
||||
extern block_t *current_block; // A pointer to the block currently being traced
|
||||
extern volatile long endstops_trigsteps[];
|
||||
extern volatile bool endstop_z_hit;
|
||||
extern bool old_z_min_endstop;
|
||||
|
||||
void quickStop();
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
temperature.h - temperature controller
|
||||
Part of Marlin
|
||||
|
||||
Copyright (c) 2011 Erik van der Zalm
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef temperature_h
|
||||
#define temperature_h
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "planner.h"
|
||||
#ifdef PID_ADD_EXTRUSION_RATE
|
||||
#include "stepper.h"
|
||||
#endif
|
||||
|
||||
// public functions
|
||||
void tp_init(); //initialise the heating
|
||||
void manage_heater(); //it is critical that this is called periodically.
|
||||
|
||||
//low leven conversion routines
|
||||
// do not use this routines and variables outsie of temperature.cpp
|
||||
int temp2analog(int celsius, uint8_t e);
|
||||
int temp2analogBed(int celsius);
|
||||
float analog2temp(int raw, uint8_t e);
|
||||
float analog2tempBed(int raw);
|
||||
extern int target_raw[EXTRUDERS];
|
||||
extern int heatingtarget_raw[EXTRUDERS];
|
||||
extern int current_raw[EXTRUDERS];
|
||||
extern int target_raw_bed;
|
||||
extern int current_raw_bed;
|
||||
#ifdef BED_LIMIT_SWITCHING
|
||||
extern int target_bed_low_temp ;
|
||||
extern int target_bed_high_temp ;
|
||||
#endif
|
||||
extern float Kp,Ki,Kd,Kc;
|
||||
extern int Ki_Max;
|
||||
|
||||
#ifdef PIDTEMP
|
||||
extern float pid_setpoint[EXTRUDERS];
|
||||
#endif
|
||||
|
||||
// #ifdef WATCHPERIOD
|
||||
extern int watch_raw[EXTRUDERS] ;
|
||||
// extern unsigned long watchmillis;
|
||||
// #endif
|
||||
|
||||
|
||||
//high level conversion routines, for use outside of temperature.cpp
|
||||
//inline so that there is no performance decrease.
|
||||
//deg=degreeCelsius
|
||||
|
||||
FORCE_INLINE float degHotend(uint8_t extruder) {
|
||||
return analog2temp(current_raw[extruder], extruder);
|
||||
};
|
||||
|
||||
FORCE_INLINE float degBed() {
|
||||
return analog2tempBed(current_raw_bed);
|
||||
};
|
||||
|
||||
FORCE_INLINE float degTargetHotend(uint8_t extruder) {
|
||||
return analog2temp(target_raw[extruder], extruder);
|
||||
};
|
||||
|
||||
FORCE_INLINE float degTargetBed() {
|
||||
return analog2tempBed(target_raw_bed);
|
||||
};
|
||||
|
||||
FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {
|
||||
target_raw[extruder] = temp2analog(celsius, extruder);
|
||||
#ifdef PIDTEMP
|
||||
pid_setpoint[extruder] = celsius;
|
||||
#endif //PIDTEMP
|
||||
};
|
||||
|
||||
FORCE_INLINE void setTargetBed(const float &celsius) {
|
||||
|
||||
target_raw_bed = temp2analogBed(celsius);
|
||||
#ifdef BED_LIMIT_SWITCHING
|
||||
if(celsius>BED_HYSTERESIS)
|
||||
{
|
||||
target_bed_low_temp= temp2analogBed(celsius-BED_HYSTERESIS);
|
||||
target_bed_high_temp= temp2analogBed(celsius+BED_HYSTERESIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_bed_low_temp=0;
|
||||
target_bed_high_temp=0;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
FORCE_INLINE bool isHeatingHotend(uint8_t extruder){
|
||||
return target_raw[extruder] > current_raw[extruder];
|
||||
};
|
||||
|
||||
FORCE_INLINE bool isHeatingBed() {
|
||||
return target_raw_bed > current_raw_bed;
|
||||
};
|
||||
|
||||
FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {
|
||||
return target_raw[extruder] < current_raw[extruder];
|
||||
};
|
||||
|
||||
FORCE_INLINE bool isCoolingBed() {
|
||||
return target_raw_bed < current_raw_bed;
|
||||
};
|
||||
|
||||
#define degHotend0() degHotend(0)
|
||||
#define degTargetHotend0() degTargetHotend(0)
|
||||
#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)
|
||||
#define isHeatingHotend0() isHeatingHotend(0)
|
||||
#define isCoolingHotend0() isCoolingHotend(0)
|
||||
#if EXTRUDERS > 1
|
||||
#define degHotend1() degHotend(1)
|
||||
#define degTargetHotend1() degTargetHotend(1)
|
||||
#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
|
||||
#define isHeatingHotend1() isHeatingHotend(1)
|
||||
#define isCoolingHotend1() isCoolingHotend(1)
|
||||
#else
|
||||
#define setTargetHotend1(_celsius) do{}while(0)
|
||||
#endif
|
||||
#if EXTRUDERS > 2
|
||||
#define degHotend2() degHotend(2)
|
||||
#define degTargetHotend2() degTargetHotend(2)
|
||||
#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
|
||||
#define isHeatingHotend2() isHeatingHotend(2)
|
||||
#define isCoolingHotend2() isCoolingHotend(2)
|
||||
#else
|
||||
#define setTargetHotend2(_celsius) do{}while(0)
|
||||
#endif
|
||||
#if EXTRUDERS > 3
|
||||
#error Invalid number of extruders
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int getHeaterPower(int heater);
|
||||
void disable_heater();
|
||||
void setWatch();
|
||||
void updatePID();
|
||||
|
||||
FORCE_INLINE void autotempShutdown(){
|
||||
#ifdef AUTOTEMP
|
||||
if(autotemp_enabled)
|
||||
{
|
||||
autotemp_enabled=false;
|
||||
if(degTargetHotend(active_extruder)>autotemp_min)
|
||||
setTargetHotend(0,active_extruder);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PID_autotune(float temp);
|
||||
|
||||
#endif
|
||||
|
||||
+608
-130
@@ -1,148 +1,626 @@
|
||||
#ifndef THERMISTORTABLES_H_
|
||||
#define THERMISTORTABLES_H_
|
||||
|
||||
#if (THERMISTORHEATER == 1) || (THERMISTORBED == 1) //100k bed thermistor
|
||||
#include "Marlin.h"
|
||||
|
||||
#define OVERSAMPLENR 16
|
||||
|
||||
#define NUMTEMPS_1 61
|
||||
const short temptable_1[NUMTEMPS_1][2] = {
|
||||
{ (23*16) , 300 },
|
||||
{ (25*16) , 295 },
|
||||
{ (27*16) , 290 },
|
||||
{ (28*16) , 285 },
|
||||
{ (31*16) , 280 },
|
||||
{ (33*16) , 275 },
|
||||
{ (35*16) , 270 },
|
||||
{ (38*16) , 265 },
|
||||
{ (41*16) , 260 },
|
||||
{ (44*16) , 255 },
|
||||
{ (48*16) , 250 },
|
||||
{ (52*16) , 245 },
|
||||
{ (56*16) , 240 },
|
||||
{ (61*16) , 235 },
|
||||
{ (66*16) , 230 },
|
||||
{ (71*16) , 225 },
|
||||
{ (78*16) , 220 },
|
||||
{ (84*16) , 215 },
|
||||
{ (92*16) , 210 },
|
||||
{ (100*16), 205 },
|
||||
{ (109*16), 200 },
|
||||
{ (120*16), 195 },
|
||||
{ (131*16), 190 },
|
||||
{ (143*16), 185 },
|
||||
{ (156*16), 180 },
|
||||
{ (171*16), 175 },
|
||||
{ (187*16), 170 },
|
||||
{ (205*16), 165 },
|
||||
{ (224*16), 160 },
|
||||
{ (245*16), 155 },
|
||||
{ (268*16), 150 },
|
||||
{ (293*16), 145 },
|
||||
{ (320*16), 140 },
|
||||
{ (348*16), 135 },
|
||||
{ (379*16), 130 },
|
||||
{ (411*16), 125 },
|
||||
{ (445*16), 120 },
|
||||
{ (480*16), 115 },
|
||||
{ (516*16), 110 },
|
||||
{ (553*16), 105 },
|
||||
{ (591*16), 100 },
|
||||
{ (628*16), 95 },
|
||||
{ (665*16), 90 },
|
||||
{ (702*16), 85 },
|
||||
{ (737*16), 80 },
|
||||
{ (770*16), 75 },
|
||||
{ (801*16), 70 },
|
||||
{ (830*16), 65 },
|
||||
{ (857*16), 60 },
|
||||
{ (881*16), 55 },
|
||||
{ (903*16), 50 },
|
||||
{ (922*16), 45 },
|
||||
{ (939*16), 40 },
|
||||
{ (954*16), 35 },
|
||||
{ (966*16), 30 },
|
||||
{ (977*16), 25 },
|
||||
{ (985*16), 20 },
|
||||
{ (993*16), 15 },
|
||||
{ (999*16), 10 },
|
||||
{ (1004*16), 5 },
|
||||
{ (1008*16), 0 } //safety
|
||||
#if (THERMISTORHEATER_0 == 1) || (THERMISTORHEATER_1 == 1) || (THERMISTORHEATER_2 == 1) || (THERMISTORBED == 1) //100k bed thermistor
|
||||
|
||||
const short temptable_1[][2] PROGMEM = {
|
||||
{ 23*OVERSAMPLENR , 300 },
|
||||
{ 25*OVERSAMPLENR , 295 },
|
||||
{ 27*OVERSAMPLENR , 290 },
|
||||
{ 28*OVERSAMPLENR , 285 },
|
||||
{ 31*OVERSAMPLENR , 280 },
|
||||
{ 33*OVERSAMPLENR , 275 },
|
||||
{ 35*OVERSAMPLENR , 270 },
|
||||
{ 38*OVERSAMPLENR , 265 },
|
||||
{ 41*OVERSAMPLENR , 260 },
|
||||
{ 44*OVERSAMPLENR , 255 },
|
||||
{ 48*OVERSAMPLENR , 250 },
|
||||
{ 52*OVERSAMPLENR , 245 },
|
||||
{ 56*OVERSAMPLENR , 240 },
|
||||
{ 61*OVERSAMPLENR , 235 },
|
||||
{ 66*OVERSAMPLENR , 230 },
|
||||
{ 71*OVERSAMPLENR , 225 },
|
||||
{ 78*OVERSAMPLENR , 220 },
|
||||
{ 84*OVERSAMPLENR , 215 },
|
||||
{ 92*OVERSAMPLENR , 210 },
|
||||
{ 100*OVERSAMPLENR , 205 },
|
||||
{ 109*OVERSAMPLENR , 200 },
|
||||
{ 120*OVERSAMPLENR , 195 },
|
||||
{ 131*OVERSAMPLENR , 190 },
|
||||
{ 143*OVERSAMPLENR , 185 },
|
||||
{ 156*OVERSAMPLENR , 180 },
|
||||
{ 171*OVERSAMPLENR , 175 },
|
||||
{ 187*OVERSAMPLENR , 170 },
|
||||
{ 205*OVERSAMPLENR , 165 },
|
||||
{ 224*OVERSAMPLENR , 160 },
|
||||
{ 245*OVERSAMPLENR , 155 },
|
||||
{ 268*OVERSAMPLENR , 150 },
|
||||
{ 293*OVERSAMPLENR , 145 },
|
||||
{ 320*OVERSAMPLENR , 140 },
|
||||
{ 348*OVERSAMPLENR , 135 },
|
||||
{ 379*OVERSAMPLENR , 130 },
|
||||
{ 411*OVERSAMPLENR , 125 },
|
||||
{ 445*OVERSAMPLENR , 120 },
|
||||
{ 480*OVERSAMPLENR , 115 },
|
||||
{ 516*OVERSAMPLENR , 110 },
|
||||
{ 553*OVERSAMPLENR , 105 },
|
||||
{ 591*OVERSAMPLENR , 100 },
|
||||
{ 628*OVERSAMPLENR , 95 },
|
||||
{ 665*OVERSAMPLENR , 90 },
|
||||
{ 702*OVERSAMPLENR , 85 },
|
||||
{ 737*OVERSAMPLENR , 80 },
|
||||
{ 770*OVERSAMPLENR , 75 },
|
||||
{ 801*OVERSAMPLENR , 70 },
|
||||
{ 830*OVERSAMPLENR , 65 },
|
||||
{ 857*OVERSAMPLENR , 60 },
|
||||
{ 881*OVERSAMPLENR , 55 },
|
||||
{ 903*OVERSAMPLENR , 50 },
|
||||
{ 922*OVERSAMPLENR , 45 },
|
||||
{ 939*OVERSAMPLENR , 40 },
|
||||
{ 954*OVERSAMPLENR , 35 },
|
||||
{ 966*OVERSAMPLENR , 30 },
|
||||
{ 977*OVERSAMPLENR , 25 },
|
||||
{ 985*OVERSAMPLENR , 20 },
|
||||
{ 993*OVERSAMPLENR , 15 },
|
||||
{ 999*OVERSAMPLENR , 10 },
|
||||
{ 1004*OVERSAMPLENR , 5 },
|
||||
{ 1008*OVERSAMPLENR , 0 } //safety
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER == 2) || (THERMISTORBED == 2) //200k bed thermistor
|
||||
#define NUMTEMPS_2 21
|
||||
const short temptable_2[NUMTEMPS_2][2] = {
|
||||
{(1*16), 848},
|
||||
{(54*16), 275},
|
||||
{(107*16), 228},
|
||||
{(160*16), 202},
|
||||
{(213*16), 185},
|
||||
{(266*16), 171},
|
||||
{(319*16), 160},
|
||||
{(372*16), 150},
|
||||
{(425*16), 141},
|
||||
{(478*16), 133},
|
||||
{(531*16), 125},
|
||||
{(584*16), 118},
|
||||
{(637*16), 110},
|
||||
{(690*16), 103},
|
||||
{(743*16), 95},
|
||||
{(796*16), 86},
|
||||
{(849*16), 77},
|
||||
{(902*16), 65},
|
||||
{(955*16), 49},
|
||||
{(1008*16), 17},
|
||||
{(1020*16), 0} //safety
|
||||
#if (THERMISTORHEATER_0 == 2) || (THERMISTORHEATER_1 == 2) || (THERMISTORHEATER_2 == 2) || (THERMISTORBED == 2) //200k bed thermistor
|
||||
const short temptable_2[][2] PROGMEM = {
|
||||
//200k ATC Semitec 204GT-2
|
||||
//Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
|
||||
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
|
||||
{1*OVERSAMPLENR, 848},
|
||||
{30*OVERSAMPLENR, 300}, //top rating 300C
|
||||
{34*OVERSAMPLENR, 290},
|
||||
{39*OVERSAMPLENR, 280},
|
||||
{46*OVERSAMPLENR, 270},
|
||||
{53*OVERSAMPLENR, 260},
|
||||
{63*OVERSAMPLENR, 250},
|
||||
{74*OVERSAMPLENR, 240},
|
||||
{87*OVERSAMPLENR, 230},
|
||||
{104*OVERSAMPLENR, 220},
|
||||
{124*OVERSAMPLENR, 210},
|
||||
{148*OVERSAMPLENR, 200},
|
||||
{176*OVERSAMPLENR, 190},
|
||||
{211*OVERSAMPLENR, 180},
|
||||
{252*OVERSAMPLENR, 170},
|
||||
{301*OVERSAMPLENR, 160},
|
||||
{357*OVERSAMPLENR, 150},
|
||||
{420*OVERSAMPLENR, 140},
|
||||
{489*OVERSAMPLENR, 130},
|
||||
{562*OVERSAMPLENR, 120},
|
||||
{636*OVERSAMPLENR, 110},
|
||||
{708*OVERSAMPLENR, 100},
|
||||
{775*OVERSAMPLENR, 90},
|
||||
{835*OVERSAMPLENR, 80},
|
||||
{884*OVERSAMPLENR, 70},
|
||||
{924*OVERSAMPLENR, 60},
|
||||
{955*OVERSAMPLENR, 50},
|
||||
{977*OVERSAMPLENR, 40},
|
||||
{993*OVERSAMPLENR, 30},
|
||||
{1004*OVERSAMPLENR, 20},
|
||||
{1012*OVERSAMPLENR, 10},
|
||||
{1016*OVERSAMPLENR, 0},
|
||||
};
|
||||
|
||||
#endif
|
||||
#if (THERMISTORHEATER == 3) || (THERMISTORBED == 3) //mendel-parts
|
||||
#define NUMTEMPS_3 28
|
||||
const short temptable_3[NUMTEMPS_3][2] = {
|
||||
{(1*16),864},
|
||||
{(21*16),300},
|
||||
{(25*16),290},
|
||||
{(29*16),280},
|
||||
{(33*16),270},
|
||||
{(39*16),260},
|
||||
{(46*16),250},
|
||||
{(54*16),240},
|
||||
{(64*16),230},
|
||||
{(75*16),220},
|
||||
{(90*16),210},
|
||||
{(107*16),200},
|
||||
{(128*16),190},
|
||||
{(154*16),180},
|
||||
{(184*16),170},
|
||||
{(221*16),160},
|
||||
{(265*16),150},
|
||||
{(316*16),140},
|
||||
{(375*16),130},
|
||||
{(441*16),120},
|
||||
{(513*16),110},
|
||||
{(588*16),100},
|
||||
{(734*16),80},
|
||||
{(856*16),60},
|
||||
{(938*16),40},
|
||||
{(986*16),20},
|
||||
{(1008*16),0},
|
||||
{(1018*16),-20}
|
||||
};
|
||||
#if (THERMISTORHEATER_0 == 3) || (THERMISTORHEATER_1 == 3) || (THERMISTORHEATER_2 == 3) || (THERMISTORBED == 3) //mendel-parts
|
||||
const short temptable_3[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR,864},
|
||||
{21*OVERSAMPLENR,300},
|
||||
{25*OVERSAMPLENR,290},
|
||||
{29*OVERSAMPLENR,280},
|
||||
{33*OVERSAMPLENR,270},
|
||||
{39*OVERSAMPLENR,260},
|
||||
{46*OVERSAMPLENR,250},
|
||||
{54*OVERSAMPLENR,240},
|
||||
{64*OVERSAMPLENR,230},
|
||||
{75*OVERSAMPLENR,220},
|
||||
{90*OVERSAMPLENR,210},
|
||||
{107*OVERSAMPLENR,200},
|
||||
{128*OVERSAMPLENR,190},
|
||||
{154*OVERSAMPLENR,180},
|
||||
{184*OVERSAMPLENR,170},
|
||||
{221*OVERSAMPLENR,160},
|
||||
{265*OVERSAMPLENR,150},
|
||||
{316*OVERSAMPLENR,140},
|
||||
{375*OVERSAMPLENR,130},
|
||||
{441*OVERSAMPLENR,120},
|
||||
{513*OVERSAMPLENR,110},
|
||||
{588*OVERSAMPLENR,100},
|
||||
{734*OVERSAMPLENR,80},
|
||||
{856*OVERSAMPLENR,60},
|
||||
{938*OVERSAMPLENR,40},
|
||||
{986*OVERSAMPLENR,20},
|
||||
{1008*OVERSAMPLENR,0},
|
||||
{1018*OVERSAMPLENR,-20}
|
||||
};
|
||||
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 4) || (THERMISTORHEATER_1 == 4) || (THERMISTORHEATER_2 == 4) || (THERMISTORBED == 4) //10k thermistor
|
||||
const short temptable_4[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 430},
|
||||
{54*OVERSAMPLENR, 137},
|
||||
{107*OVERSAMPLENR, 107},
|
||||
{160*OVERSAMPLENR, 91},
|
||||
{213*OVERSAMPLENR, 80},
|
||||
{266*OVERSAMPLENR, 71},
|
||||
{319*OVERSAMPLENR, 64},
|
||||
{372*OVERSAMPLENR, 57},
|
||||
{425*OVERSAMPLENR, 51},
|
||||
{478*OVERSAMPLENR, 46},
|
||||
{531*OVERSAMPLENR, 41},
|
||||
{584*OVERSAMPLENR, 35},
|
||||
{637*OVERSAMPLENR, 30},
|
||||
{690*OVERSAMPLENR, 25},
|
||||
{743*OVERSAMPLENR, 20},
|
||||
{796*OVERSAMPLENR, 14},
|
||||
{849*OVERSAMPLENR, 7},
|
||||
{902*OVERSAMPLENR, 0},
|
||||
{955*OVERSAMPLENR, -11},
|
||||
{1008*OVERSAMPLENR, -35}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if THERMISTORHEATER == 1
|
||||
#define NUMTEMPS NUMTEMPS_1
|
||||
#define temptable temptable_1
|
||||
#elif THERMISTORHEATER == 2
|
||||
#define NUMTEMPS NUMTEMPS_2
|
||||
#define temptable temptable_2
|
||||
#elif THERMISTORHEATER == 3
|
||||
#define NUMTEMPS NUMTEMPS_3
|
||||
#define temptable temptable_3
|
||||
#if (THERMISTORHEATER_0 == 5) || (THERMISTORHEATER_1 == 5) || (THERMISTORHEATER_2 == 5) || (THERMISTORBED == 5) //100k ParCan thermistor (104GT-2)
|
||||
const short temptable_5[][2] PROGMEM = {
|
||||
// ATC Semitec 104GT-2 (Used in ParCan)
|
||||
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
|
||||
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
|
||||
{1*OVERSAMPLENR, 713},
|
||||
{17*OVERSAMPLENR, 300}, //top rating 300C
|
||||
{20*OVERSAMPLENR, 290},
|
||||
{23*OVERSAMPLENR, 280},
|
||||
{27*OVERSAMPLENR, 270},
|
||||
{31*OVERSAMPLENR, 260},
|
||||
{37*OVERSAMPLENR, 250},
|
||||
{43*OVERSAMPLENR, 240},
|
||||
{51*OVERSAMPLENR, 230},
|
||||
{61*OVERSAMPLENR, 220},
|
||||
{73*OVERSAMPLENR, 210},
|
||||
{87*OVERSAMPLENR, 200},
|
||||
{106*OVERSAMPLENR, 190},
|
||||
{128*OVERSAMPLENR, 180},
|
||||
{155*OVERSAMPLENR, 170},
|
||||
{189*OVERSAMPLENR, 160},
|
||||
{230*OVERSAMPLENR, 150},
|
||||
{278*OVERSAMPLENR, 140},
|
||||
{336*OVERSAMPLENR, 130},
|
||||
{402*OVERSAMPLENR, 120},
|
||||
{476*OVERSAMPLENR, 110},
|
||||
{554*OVERSAMPLENR, 100},
|
||||
{635*OVERSAMPLENR, 90},
|
||||
{713*OVERSAMPLENR, 80},
|
||||
{784*OVERSAMPLENR, 70},
|
||||
{846*OVERSAMPLENR, 60},
|
||||
{897*OVERSAMPLENR, 50},
|
||||
{937*OVERSAMPLENR, 40},
|
||||
{966*OVERSAMPLENR, 30},
|
||||
{986*OVERSAMPLENR, 20},
|
||||
{1000*OVERSAMPLENR, 10},
|
||||
{1010*OVERSAMPLENR, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (THERMISTORHEATER_0 == 6) || (THERMISTORHEATER_1 == 6) || (THERMISTORHEATER_2 == 6) || (THERMISTORBED == 6) // 100k Epcos thermistor
|
||||
const short temptable_6[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 350},
|
||||
{28*OVERSAMPLENR, 250}, //top rating 250C
|
||||
{31*OVERSAMPLENR, 245},
|
||||
{35*OVERSAMPLENR, 240},
|
||||
{39*OVERSAMPLENR, 235},
|
||||
{42*OVERSAMPLENR, 230},
|
||||
{44*OVERSAMPLENR, 225},
|
||||
{49*OVERSAMPLENR, 220},
|
||||
{53*OVERSAMPLENR, 215},
|
||||
{62*OVERSAMPLENR, 210},
|
||||
{71*OVERSAMPLENR, 205}, //fitted graphically
|
||||
{78*OVERSAMPLENR, 200}, //fitted graphically
|
||||
{94*OVERSAMPLENR, 190},
|
||||
{102*OVERSAMPLENR, 185},
|
||||
{116*OVERSAMPLENR, 170},
|
||||
{143*OVERSAMPLENR, 160},
|
||||
{183*OVERSAMPLENR, 150},
|
||||
{223*OVERSAMPLENR, 140},
|
||||
{270*OVERSAMPLENR, 130},
|
||||
{318*OVERSAMPLENR, 120},
|
||||
{383*OVERSAMPLENR, 110},
|
||||
{413*OVERSAMPLENR, 105},
|
||||
{439*OVERSAMPLENR, 100},
|
||||
{484*OVERSAMPLENR, 95},
|
||||
{513*OVERSAMPLENR, 90},
|
||||
{607*OVERSAMPLENR, 80},
|
||||
{664*OVERSAMPLENR, 70},
|
||||
{781*OVERSAMPLENR, 60},
|
||||
{810*OVERSAMPLENR, 55},
|
||||
{849*OVERSAMPLENR, 50},
|
||||
{914*OVERSAMPLENR, 45},
|
||||
{914*OVERSAMPLENR, 40},
|
||||
{935*OVERSAMPLENR, 35},
|
||||
{954*OVERSAMPLENR, 30},
|
||||
{970*OVERSAMPLENR, 25},
|
||||
{978*OVERSAMPLENR, 22},
|
||||
{1008*OVERSAMPLENR, 3}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (THERMISTORHEATER_0 == 7) || (THERMISTORHEATER_1 == 7) || (THERMISTORHEATER_2 == 7) || (THERMISTORBED == 7) // 100k Honeywell 135-104LAG-J01
|
||||
const short temptable_7[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 500},
|
||||
{46*OVERSAMPLENR, 270}, //top rating 300C
|
||||
{50*OVERSAMPLENR, 265},
|
||||
{54*OVERSAMPLENR, 260},
|
||||
{58*OVERSAMPLENR, 255},
|
||||
{62*OVERSAMPLENR, 250},
|
||||
{67*OVERSAMPLENR, 245},
|
||||
{72*OVERSAMPLENR, 240},
|
||||
{79*OVERSAMPLENR, 235},
|
||||
{85*OVERSAMPLENR, 230},
|
||||
{91*OVERSAMPLENR, 225},
|
||||
{99*OVERSAMPLENR, 220},
|
||||
{107*OVERSAMPLENR, 215},
|
||||
{116*OVERSAMPLENR, 210},
|
||||
{126*OVERSAMPLENR, 205},
|
||||
{136*OVERSAMPLENR, 200},
|
||||
{149*OVERSAMPLENR, 195},
|
||||
{160*OVERSAMPLENR, 190},
|
||||
{175*OVERSAMPLENR, 185},
|
||||
{191*OVERSAMPLENR, 180},
|
||||
{209*OVERSAMPLENR, 175},
|
||||
{224*OVERSAMPLENR, 170},
|
||||
{246*OVERSAMPLENR, 165},
|
||||
{267*OVERSAMPLENR, 160},
|
||||
{293*OVERSAMPLENR, 155},
|
||||
{316*OVERSAMPLENR, 150},
|
||||
{340*OVERSAMPLENR, 145},
|
||||
{364*OVERSAMPLENR, 140},
|
||||
{396*OVERSAMPLENR, 135},
|
||||
{425*OVERSAMPLENR, 130},
|
||||
{460*OVERSAMPLENR, 125},
|
||||
{489*OVERSAMPLENR, 120},
|
||||
{526*OVERSAMPLENR, 115},
|
||||
{558*OVERSAMPLENR, 110},
|
||||
{591*OVERSAMPLENR, 105},
|
||||
{628*OVERSAMPLENR, 100},
|
||||
{660*OVERSAMPLENR, 95},
|
||||
{696*OVERSAMPLENR, 90},
|
||||
{733*OVERSAMPLENR, 85},
|
||||
{761*OVERSAMPLENR, 80},
|
||||
{794*OVERSAMPLENR, 75},
|
||||
{819*OVERSAMPLENR, 70},
|
||||
{847*OVERSAMPLENR, 65},
|
||||
{870*OVERSAMPLENR, 60},
|
||||
{892*OVERSAMPLENR, 55},
|
||||
{911*OVERSAMPLENR, 50},
|
||||
{929*OVERSAMPLENR, 45},
|
||||
{944*OVERSAMPLENR, 40},
|
||||
{959*OVERSAMPLENR, 35},
|
||||
{971*OVERSAMPLENR, 30},
|
||||
{981*OVERSAMPLENR, 25},
|
||||
{989*OVERSAMPLENR, 20},
|
||||
{994*OVERSAMPLENR, 15},
|
||||
{1001*OVERSAMPLENR, 10},
|
||||
{1005*OVERSAMPLENR, 5}
|
||||
};
|
||||
#endif
|
||||
//
|
||||
#if (THERMISTORHEATER_0 == 100) || (THERMISTORHEATER_1 == 100) || (THERMISTORHEATER_2 == 100) || (THERMISTORBED == 100) // 100k DO-35 NTC
|
||||
const short temptable_100[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 929},
|
||||
{36*OVERSAMPLENR, 299},
|
||||
{71*OVERSAMPLENR, 246},
|
||||
{106*OVERSAMPLENR, 217},
|
||||
{141*OVERSAMPLENR, 198},
|
||||
{176*OVERSAMPLENR, 184},
|
||||
{211*OVERSAMPLENR, 173},
|
||||
{246*OVERSAMPLENR, 163},
|
||||
{281*OVERSAMPLENR, 154},
|
||||
{316*OVERSAMPLENR, 147},
|
||||
{351*OVERSAMPLENR, 140},
|
||||
{386*OVERSAMPLENR, 134},
|
||||
{421*OVERSAMPLENR, 128},
|
||||
{456*OVERSAMPLENR, 122},
|
||||
{491*OVERSAMPLENR, 117},
|
||||
{526*OVERSAMPLENR, 112},
|
||||
{561*OVERSAMPLENR, 107},
|
||||
{596*OVERSAMPLENR, 102},
|
||||
{631*OVERSAMPLENR, 97},
|
||||
{666*OVERSAMPLENR, 91},
|
||||
{701*OVERSAMPLENR, 86},
|
||||
{736*OVERSAMPLENR, 81},
|
||||
{771*OVERSAMPLENR, 76},
|
||||
{806*OVERSAMPLENR, 70},
|
||||
{841*OVERSAMPLENR, 63},
|
||||
{876*OVERSAMPLENR, 56},
|
||||
{911*OVERSAMPLENR, 48},
|
||||
{946*OVERSAMPLENR, 38},
|
||||
{981*OVERSAMPLENR, 23},
|
||||
{1005*OVERSAMPLENR, 5},
|
||||
{1016*OVERSAMPLENR, 0}
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 101) || (THERMISTORHEATER_1 == 101) || (THERMISTORHEATER_2 == 101) || (THERMISTORBED == 101) // 100k Honeywell 135-104LAG-J01
|
||||
const short temptable_101[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 704},
|
||||
{54*OVERSAMPLENR, 216},
|
||||
{107*OVERSAMPLENR, 175},
|
||||
{160*OVERSAMPLENR, 152},
|
||||
{213*OVERSAMPLENR, 137},
|
||||
{266*OVERSAMPLENR, 125},
|
||||
{319*OVERSAMPLENR, 115},
|
||||
{372*OVERSAMPLENR, 106},
|
||||
{425*OVERSAMPLENR, 99},
|
||||
{478*OVERSAMPLENR, 91},
|
||||
{531*OVERSAMPLENR, 85},
|
||||
{584*OVERSAMPLENR, 78},
|
||||
{637*OVERSAMPLENR, 71},
|
||||
{690*OVERSAMPLENR, 65},
|
||||
{743*OVERSAMPLENR, 58},
|
||||
{796*OVERSAMPLENR, 50},
|
||||
{849*OVERSAMPLENR, 42},
|
||||
{902*OVERSAMPLENR, 31},
|
||||
{955*OVERSAMPLENR, 17},
|
||||
{1008*OVERSAMPLENR, 0}
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 102) || (THERMISTORHEATER_1 == 102) || (THERMISTORHEATER_2 == 102) || (THERMISTORBED == 102) // EPCOS G57540
|
||||
const short temptable_102[][2] PROGMEM = {
|
||||
{15*OVERSAMPLENR,286},
|
||||
{16*OVERSAMPLENR,282},
|
||||
{17*OVERSAMPLENR,278},
|
||||
{18*OVERSAMPLENR,274},
|
||||
{19*OVERSAMPLENR,270},
|
||||
{20*OVERSAMPLENR,266},
|
||||
{21*OVERSAMPLENR,262},
|
||||
{22*OVERSAMPLENR,258},
|
||||
{23*OVERSAMPLENR,254},
|
||||
{25*OVERSAMPLENR,250},
|
||||
{27*OVERSAMPLENR,246},
|
||||
{28*OVERSAMPLENR,242},
|
||||
{31*OVERSAMPLENR,238},
|
||||
{33*OVERSAMPLENR,234},
|
||||
{35*OVERSAMPLENR,230},
|
||||
{38*OVERSAMPLENR,226},
|
||||
{41*OVERSAMPLENR,222},
|
||||
{44*OVERSAMPLENR,218},
|
||||
{48*OVERSAMPLENR,214},
|
||||
{52*OVERSAMPLENR,210},
|
||||
{56*OVERSAMPLENR,206},
|
||||
{61*OVERSAMPLENR,202},
|
||||
{66*OVERSAMPLENR,198},
|
||||
{71*OVERSAMPLENR,194},
|
||||
{78*OVERSAMPLENR,190},
|
||||
{84*OVERSAMPLENR,186},
|
||||
{92*OVERSAMPLENR,182},
|
||||
{100*OVERSAMPLENR,178},
|
||||
{109*OVERSAMPLENR,174},
|
||||
{120*OVERSAMPLENR,170},
|
||||
{131*OVERSAMPLENR,166},
|
||||
{143*OVERSAMPLENR,162},
|
||||
{156*OVERSAMPLENR,158},
|
||||
{171*OVERSAMPLENR,154},
|
||||
{187*OVERSAMPLENR,150},
|
||||
{205*OVERSAMPLENR,146},
|
||||
{224*OVERSAMPLENR,142},
|
||||
{224*OVERSAMPLENR,160},
|
||||
{245*OVERSAMPLENR,155},
|
||||
{268*OVERSAMPLENR,150},
|
||||
{293*OVERSAMPLENR,145},
|
||||
{320*OVERSAMPLENR,140},
|
||||
{348*OVERSAMPLENR,135},
|
||||
{379*OVERSAMPLENR,130},
|
||||
{411*OVERSAMPLENR,125},
|
||||
{480*OVERSAMPLENR,115},
|
||||
{553*OVERSAMPLENR,105},
|
||||
{628*OVERSAMPLENR,95},
|
||||
{702*OVERSAMPLENR,85},
|
||||
{770*OVERSAMPLENR,75},
|
||||
{830*OVERSAMPLENR,65},
|
||||
{881*OVERSAMPLENR,55},
|
||||
{922*OVERSAMPLENR,45},
|
||||
{954*OVERSAMPLENR,35},
|
||||
{977*OVERSAMPLENR,25},
|
||||
{993*OVERSAMPLENR,15},
|
||||
{999*OVERSAMPLENR,10},
|
||||
{1008*OVERSAMPLENR,0},
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 103) || (THERMISTORHEATER_1 == 103) || (THERMISTORHEATER_2 == 103) || (THERMISTORBED == 103) // EPCOS G57540
|
||||
const short temptable_103[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 628},
|
||||
{187*OVERSAMPLENR, 156},
|
||||
{218*OVERSAMPLENR, 148},
|
||||
{249*OVERSAMPLENR, 141},
|
||||
{280*OVERSAMPLENR, 135},
|
||||
{311*OVERSAMPLENR, 129},
|
||||
{342*OVERSAMPLENR, 124},
|
||||
{373*OVERSAMPLENR, 120},
|
||||
{404*OVERSAMPLENR, 115},
|
||||
{435*OVERSAMPLENR, 111},
|
||||
{466*OVERSAMPLENR, 107},
|
||||
{497*OVERSAMPLENR, 103},
|
||||
{528*OVERSAMPLENR, 99},
|
||||
{559*OVERSAMPLENR, 96},
|
||||
{590*OVERSAMPLENR, 92},
|
||||
{621*OVERSAMPLENR, 88},
|
||||
{652*OVERSAMPLENR, 84},
|
||||
{683*OVERSAMPLENR, 81},
|
||||
{714*OVERSAMPLENR, 77},
|
||||
{745*OVERSAMPLENR, 73},
|
||||
{776*OVERSAMPLENR, 68},
|
||||
{807*OVERSAMPLENR, 64},
|
||||
{838*OVERSAMPLENR, 59},
|
||||
{869*OVERSAMPLENR, 54},
|
||||
{900*OVERSAMPLENR, 48},
|
||||
{931*OVERSAMPLENR, 40},
|
||||
{962*OVERSAMPLENR, 31},
|
||||
{993*OVERSAMPLENR, 17},
|
||||
{1008*OVERSAMPLENR,0}
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 104) || (THERMISTORHEATER_1 == 104) || (THERMISTORHEATER_2 == 104) || (THERMISTORBED == 104) // EPCOS G57540G103F - r2=4k7
|
||||
const short temptable_104[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 599},
|
||||
{54*OVERSAMPLENR, 160},
|
||||
{107*OVERSAMPLENR, 123},
|
||||
{160*OVERSAMPLENR, 103},
|
||||
{213*OVERSAMPLENR, 90},
|
||||
{266*OVERSAMPLENR, 79},
|
||||
{319*OVERSAMPLENR, 70},
|
||||
{372*OVERSAMPLENR, 62},
|
||||
{425*OVERSAMPLENR, 55},
|
||||
{478*OVERSAMPLENR, 49},
|
||||
{531*OVERSAMPLENR, 43},
|
||||
{584*OVERSAMPLENR, 37},
|
||||
{637*OVERSAMPLENR, 31},
|
||||
{690*OVERSAMPLENR, 25},
|
||||
{743*OVERSAMPLENR, 19},
|
||||
{796*OVERSAMPLENR, 12},
|
||||
{849*OVERSAMPLENR, 5},
|
||||
{902*OVERSAMPLENR, -3},
|
||||
{955*OVERSAMPLENR, -16},
|
||||
{1008*OVERSAMPLENR, -42}
|
||||
};
|
||||
#endif
|
||||
#if (THERMISTORHEATER_0 == 105) || (THERMISTORHEATER_1 == 105) || (THERMISTORHEATER_2 == 105) || (THERMISTORBED == 105) // EPCOS G57540G103F - r2=10k
|
||||
const short temptable_105[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 460},
|
||||
{54*OVERSAMPLENR, 123},
|
||||
{107*OVERSAMPLENR, 92},
|
||||
{160*OVERSAMPLENR, 75},
|
||||
{213*OVERSAMPLENR, 63},
|
||||
{266*OVERSAMPLENR, 54},
|
||||
{319*OVERSAMPLENR, 46},
|
||||
{372*OVERSAMPLENR, 40},
|
||||
{425*OVERSAMPLENR, 34},
|
||||
{478*OVERSAMPLENR, 28},
|
||||
{531*OVERSAMPLENR, 23},
|
||||
{584*OVERSAMPLENR, 17},
|
||||
{637*OVERSAMPLENR, 12},
|
||||
{690*OVERSAMPLENR, 7},
|
||||
{743*OVERSAMPLENR, 2},
|
||||
{796*OVERSAMPLENR, -3},
|
||||
{849*OVERSAMPLENR, -10},
|
||||
{902*OVERSAMPLENR, -18},
|
||||
{955*OVERSAMPLENR, -29},
|
||||
{1008*OVERSAMPLENR, -53}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (THERMISTORHEATER_0 == 110) || (THERMISTORHEATER_1 == 110) || (THERMISTORHEATER_2 == 110) || (THERMISTORBED == 110) // RS thermistor 198-961
|
||||
const short temptable_110[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 704},
|
||||
{15*OVERSAMPLENR, 280},
|
||||
{21*OVERSAMPLENR, 266},
|
||||
{41*OVERSAMPLENR, 234},
|
||||
{61*OVERSAMPLENR, 208},
|
||||
{81*OVERSAMPLENR, 191},
|
||||
{101*OVERSAMPLENR, 178},
|
||||
{121*OVERSAMPLENR, 168},
|
||||
{141*OVERSAMPLENR, 159},
|
||||
{161*OVERSAMPLENR, 152},
|
||||
{181*OVERSAMPLENR, 146},
|
||||
{221*OVERSAMPLENR, 135},
|
||||
{261*OVERSAMPLENR, 126},
|
||||
{301*OVERSAMPLENR, 118},
|
||||
{341*OVERSAMPLENR, 111},
|
||||
{381*OVERSAMPLENR, 105},
|
||||
{421*OVERSAMPLENR, 99},
|
||||
{461*OVERSAMPLENR, 94},
|
||||
{501*OVERSAMPLENR, 88},
|
||||
{541*OVERSAMPLENR, 83},
|
||||
{581*OVERSAMPLENR, 78},
|
||||
{621*OVERSAMPLENR, 73},
|
||||
{661*OVERSAMPLENR, 68},
|
||||
{741*OVERSAMPLENR, 58},
|
||||
{781*OVERSAMPLENR, 52},
|
||||
{821*OVERSAMPLENR, 46},
|
||||
{861*OVERSAMPLENR, 40},
|
||||
{901*OVERSAMPLENR, 32},
|
||||
{981*OVERSAMPLENR, 7},
|
||||
{1008*OVERSAMPLENR, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (THERMISTORHEATER_0 == 111) || (THERMISTORHEATER_1 == 111) || (THERMISTORHEATER_2 == 111) || (THERMISTORBED == 111) //100k EPCOS
|
||||
const short temptable_111[][2] PROGMEM = {
|
||||
{1*OVERSAMPLENR, 704},
|
||||
{54*OVERSAMPLENR, 216},
|
||||
{107*OVERSAMPLENR, 175},
|
||||
{160*OVERSAMPLENR, 152},
|
||||
{213*OVERSAMPLENR, 137},
|
||||
{266*OVERSAMPLENR, 125},
|
||||
{319*OVERSAMPLENR, 115},
|
||||
{372*OVERSAMPLENR, 106},
|
||||
{425*OVERSAMPLENR, 99},
|
||||
{478*OVERSAMPLENR, 91},
|
||||
{531*OVERSAMPLENR, 85},
|
||||
{584*OVERSAMPLENR, 78},
|
||||
{637*OVERSAMPLENR, 71},
|
||||
{690*OVERSAMPLENR, 65},
|
||||
{743*OVERSAMPLENR, 58},
|
||||
{796*OVERSAMPLENR, 50},
|
||||
{849*OVERSAMPLENR, 42},
|
||||
{902*OVERSAMPLENR, 31},
|
||||
{955*OVERSAMPLENR, 17},
|
||||
{1008*OVERSAMPLENR, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#define _TT_NAME(_N) temptable_ ## _N
|
||||
#define TT_NAME(_N) _TT_NAME(_N)
|
||||
|
||||
#ifdef THERMISTORHEATER_0
|
||||
#define heater_0_temptable TT_NAME(THERMISTORHEATER_0)
|
||||
#define heater_0_temptable_len (sizeof(heater_0_temptable)/sizeof(*heater_0_temptable))
|
||||
#else
|
||||
#error No heater thermistor table specified
|
||||
#ifdef HEATER_0_USES_THERMISTOR
|
||||
#error No heater 0 thermistor table specified
|
||||
#else // HEATER_0_USES_THERMISTOR
|
||||
#define heater_0_temptable 0
|
||||
#define heater_0_temptable_len 0
|
||||
#endif // HEATER_0_USES_THERMISTOR
|
||||
#endif
|
||||
|
||||
#ifdef THERMISTORHEATER_1
|
||||
#define heater_1_temptable TT_NAME(THERMISTORHEATER_1)
|
||||
#define heater_1_temptable_len (sizeof(heater_1_temptable)/sizeof(*heater_1_temptable))
|
||||
#else
|
||||
#ifdef HEATER_1_USES_THERMISTOR
|
||||
#error No heater 1 thermistor table specified
|
||||
#else // HEATER_1_USES_THERMISTOR
|
||||
#define heater_1_temptable 0
|
||||
#define heater_1_temptable_len 0
|
||||
#endif // HEATER_1_USES_THERMISTOR
|
||||
#endif
|
||||
|
||||
#ifdef THERMISTORHEATER_2
|
||||
#define heater_2_temptable TT_NAME(THERMISTORHEATER_2)
|
||||
#define heater_2_temptable_len (sizeof(heater_2_temptable)/sizeof(*heater_2_temptable))
|
||||
#else
|
||||
#ifdef HEATER_2_USES_THERMISTOR
|
||||
#error No heater 2 thermistor table specified
|
||||
#else // HEATER_2_USES_THERMISTOR
|
||||
#define heater_2_temptable 0
|
||||
#define heater_2_temptable_len 0
|
||||
#endif // HEATER_2_USES_THERMISTOR
|
||||
#endif
|
||||
|
||||
#ifdef THERMISTORBED
|
||||
#define bedtemptable TT_NAME(THERMISTORBED)
|
||||
#define bedtemptable_len (sizeof(bedtemptable)/sizeof(*bedtemptable))
|
||||
#else
|
||||
#ifdef BED_USES_THERMISTOR
|
||||
#error No bed thermistor table specified
|
||||
#endif // BED_USES_THERMISTOR
|
||||
#endif
|
||||
|
||||
#endif //THERMISTORTABLES_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#ifndef ULTRALCD_H
|
||||
#define ULTRALCD_H
|
||||
#include "Marlin.h"
|
||||
#ifdef ULTRA_LCD
|
||||
#include <LiquidCrystal.h>
|
||||
void lcd_status();
|
||||
void lcd_init();
|
||||
void lcd_status(const char* message);
|
||||
void beep();
|
||||
void buttons_init();
|
||||
void buttons_check();
|
||||
|
||||
#define LCD_UPDATE_INTERVAL 100
|
||||
#define STATUSTIMEOUT 15000
|
||||
extern LiquidCrystal lcd;
|
||||
extern volatile char buttons; //the last checked buttons in a bit array.
|
||||
|
||||
#ifdef NEWPANEL
|
||||
#define EN_C (1<<BLEN_C)
|
||||
#define EN_B (1<<BLEN_B)
|
||||
#define EN_A (1<<BLEN_A)
|
||||
|
||||
#define CLICKED (buttons&EN_C)
|
||||
#define BLOCK {blocking=millis()+blocktime;}
|
||||
#if (SDCARDDETECT > -1)
|
||||
#ifdef SDCARDDETECTINVERTED
|
||||
#define CARDINSERTED (READ(SDCARDDETECT)!=0)
|
||||
#else
|
||||
#define CARDINSERTED (READ(SDCARDDETECT)==0)
|
||||
#endif
|
||||
#endif //SDCARDTETECTINVERTED
|
||||
|
||||
#else
|
||||
|
||||
//atomatic, do not change
|
||||
#define B_LE (1<<BL_LE)
|
||||
#define B_UP (1<<BL_UP)
|
||||
#define B_MI (1<<BL_MI)
|
||||
#define B_DW (1<<BL_DW)
|
||||
#define B_RI (1<<BL_RI)
|
||||
#define B_ST (1<<BL_ST)
|
||||
#define EN_B (1<<BLEN_B)
|
||||
#define EN_A (1<<BLEN_A)
|
||||
|
||||
#define CLICKED ((buttons&B_MI)||(buttons&B_ST))
|
||||
#define BLOCK {blocking[BL_MI]=millis()+blocktime;blocking[BL_ST]=millis()+blocktime;}
|
||||
|
||||
#endif
|
||||
|
||||
// blocking time for recognizing a new keypress of one key, ms
|
||||
#define blocktime 500
|
||||
#define lcdslow 5
|
||||
|
||||
enum MainStatus{Main_Status, Main_Menu, Main_Prepare,Sub_PrepareMove, Main_Control, Main_SD,Sub_TempControl,Sub_MotionControl,Sub_RetractControl};
|
||||
|
||||
class MainMenu{
|
||||
public:
|
||||
MainMenu();
|
||||
void update();
|
||||
int8_t activeline;
|
||||
MainStatus status;
|
||||
uint8_t displayStartingRow;
|
||||
|
||||
void showStatus();
|
||||
void showMainMenu();
|
||||
void showPrepare();
|
||||
void showTune();
|
||||
void showControl();
|
||||
void showControlMotion();
|
||||
void showControlTemp();
|
||||
void showControlRetract();
|
||||
void showAxisMove();
|
||||
void showSD();
|
||||
bool force_lcd_update;
|
||||
long lastencoderpos;
|
||||
int8_t lineoffset;
|
||||
int8_t lastlineoffset;
|
||||
|
||||
bool linechanging;
|
||||
|
||||
bool tune;
|
||||
|
||||
private:
|
||||
FORCE_INLINE void updateActiveLines(const uint8_t &maxlines,volatile long &encoderpos)
|
||||
{
|
||||
if(linechanging) return; // an item is changint its value, do not switch lines hence
|
||||
lastlineoffset=lineoffset;
|
||||
long curencoderpos=encoderpos;
|
||||
force_lcd_update=false;
|
||||
if( (abs(curencoderpos-lastencoderpos)<lcdslow) )
|
||||
{
|
||||
lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?' ':' ');
|
||||
if(curencoderpos<0)
|
||||
{
|
||||
lineoffset--;
|
||||
if(lineoffset<0) lineoffset=0;
|
||||
curencoderpos=lcdslow-1;
|
||||
}
|
||||
if(curencoderpos>(LCD_HEIGHT-1+1)*lcdslow)
|
||||
{
|
||||
lineoffset++;
|
||||
curencoderpos=(LCD_HEIGHT-1)*lcdslow;
|
||||
if(lineoffset>(maxlines+1-LCD_HEIGHT))
|
||||
lineoffset=maxlines+1-LCD_HEIGHT;
|
||||
if(curencoderpos>maxlines*lcdslow)
|
||||
curencoderpos=maxlines*lcdslow;
|
||||
}
|
||||
lastencoderpos=encoderpos=curencoderpos;
|
||||
activeline=curencoderpos/lcdslow;
|
||||
if(activeline<0) activeline=0;
|
||||
if(activeline>LCD_HEIGHT-1) activeline=LCD_HEIGHT-1;
|
||||
if(activeline>maxlines)
|
||||
{
|
||||
activeline=maxlines;
|
||||
curencoderpos=maxlines*lcdslow;
|
||||
}
|
||||
if(lastlineoffset!=lineoffset)
|
||||
force_lcd_update=true;
|
||||
lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003');
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void clearIfNecessary()
|
||||
{
|
||||
if(lastlineoffset!=lineoffset ||force_lcd_update)
|
||||
{
|
||||
force_lcd_update=true;
|
||||
lcd.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//conversion routines, could need some overworking
|
||||
char *ftostr51(const float &x);
|
||||
char *ftostr52(const float &x);
|
||||
char *ftostr31(const float &x);
|
||||
char *ftostr3(const float &x);
|
||||
|
||||
|
||||
#define LCD_INIT lcd_init();
|
||||
#define LCD_MESSAGE(x) lcd_status(x);
|
||||
#define LCD_MESSAGEPGM(x) lcd_statuspgm(MYPGM(x));
|
||||
#define LCD_STATUS lcd_status()
|
||||
#else //no lcd
|
||||
#define LCD_INIT
|
||||
#define LCD_STATUS
|
||||
#define LCD_MESSAGE(x)
|
||||
#define LCD_MESSAGEPGM(x)
|
||||
FORCE_INLINE void lcd_status() {};
|
||||
|
||||
#define CLICKED false
|
||||
#define BLOCK ;
|
||||
#endif
|
||||
|
||||
void lcd_statuspgm(const char* message);
|
||||
|
||||
char *ftostr3(const float &x);
|
||||
char *itostr2(const uint8_t &x);
|
||||
char *ftostr31(const float &x);
|
||||
char *ftostr32(const float &x);
|
||||
char *itostr31(const int &xx);
|
||||
char *itostr3(const int &xx);
|
||||
char *itostr4(const int &xx);
|
||||
char *ftostr51(const float &x);
|
||||
#endif //ULTRALCD
|
||||
+2644
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
#ifndef WATCHDOG_H
|
||||
#define WATCHDOG_H
|
||||
#include "Marlin.h"
|
||||
#ifdef USE_WATCHDOG
|
||||
|
||||
// intialise watch dog with a 1 sec interrupt time
|
||||
void wd_init();
|
||||
// pad the dog/reset watchdog. MUST be called at least every second after the first wd_init or avr will go into emergency procedures..
|
||||
void wd_reset();
|
||||
|
||||
#else
|
||||
FORCE_INLINE void wd_init() {};
|
||||
FORCE_INLINE void wd_reset() {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifdef USE_WATCHDOG
|
||||
#include "Marlin.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
//===========================================================================
|
||||
//=============================private variables ============================
|
||||
//===========================================================================
|
||||
|
||||
static volatile uint8_t timeout_seconds=0;
|
||||
|
||||
void(* ctrlaltdelete) (void) = 0; //does not work on my atmega2560
|
||||
|
||||
//===========================================================================
|
||||
//=============================functinos ============================
|
||||
//===========================================================================
|
||||
|
||||
|
||||
/// intialise watch dog with a 1 sec interrupt time
|
||||
void wd_init()
|
||||
{
|
||||
WDTCSR |= (1<<WDCE )|(1<<WDE ); //allow changes
|
||||
WDTCSR = (1<<WDCE )|(1<<WDE )|(1<<WDP3 )|(1<<WDP0); // Reset after 8 sec.
|
||||
// WDTCSR = (1<<WDIF)|(1<<WDIE)| (1<<WDCE )|(1<<WDE )| (1<<WDP3) | (1<<WDP0);
|
||||
}
|
||||
|
||||
/// reset watchdog. MUST be called every 1s after init or avr will reset.
|
||||
void wd_reset()
|
||||
{
|
||||
wdt_reset();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//=============================ISR ============================
|
||||
//===========================================================================
|
||||
|
||||
//Watchdog timer interrupt, called if main program blocks >1sec
|
||||
ISR(WDT_vect)
|
||||
{
|
||||
if(timeout_seconds++ >= WATCHDOG_TIMEOUT)
|
||||
{
|
||||
|
||||
#ifdef RESET_MANUAL
|
||||
LCD_MESSAGEPGM("Please Reset!");
|
||||
LCD_STATUS;
|
||||
SERIAL_ERROR_START;
|
||||
SERIAL_ERRORLNPGM("Something is wrong, please turn off the printer.");
|
||||
#else
|
||||
LCD_MESSAGEPGM("Timeout, resetting!");
|
||||
LCD_STATUS;
|
||||
#endif
|
||||
//disable watchdog, it will survife reboot.
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = 0;
|
||||
#ifdef RESET_MANUAL
|
||||
kill(); //kill blocks
|
||||
while(1); //wait for user or serial reset
|
||||
#else
|
||||
ctrlaltdelete();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_WATCHDOG */
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* fixed by this patch:
|
||||
* http://code.google.com/p/arduino/issues/detail?id=604
|
||||
* */
|
||||
/*
|
||||
wiring.h - Partial implementation of the Wiring API for the ATmega8.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef Wiring_h
|
||||
#define Wiring_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <stdlib.h>
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#if __AVR_LIBC_VERSION__ < 10701UL
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#endif
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
|
||||
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
void digitalWrite(uint8_t, uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(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 setup(void);
|
||||
void loop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
wiring_serial.c - serial functions.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
Modified 29 January 2009, Marius Kintel for Sanguino - http://www.sanguino.cc/
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
// Define constants and variables for buffering incoming serial data. We're
|
||||
// using a ring buffer (I think), in which rx_buffer_head is the index of the
|
||||
// location to which to write the next incoming character and rx_buffer_tail
|
||||
// is the index of the location from which to read.
|
||||
#define RX_BUFFER_SIZE 128
|
||||
#define RX_BUFFER_MASK 0x7f
|
||||
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
unsigned char rx_buffer[2][RX_BUFFER_SIZE];
|
||||
int rx_buffer_head[2] = {0, 0};
|
||||
int rx_buffer_tail[2] = {0, 0};
|
||||
#else
|
||||
unsigned char rx_buffer[1][RX_BUFFER_SIZE];
|
||||
int rx_buffer_head[1] = {0};
|
||||
int rx_buffer_tail[1] = {0};
|
||||
#endif
|
||||
|
||||
|
||||
#define BEGIN_SERIAL(uart_, baud_) \
|
||||
{ \
|
||||
UBRR##uart_##H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8; \
|
||||
UBRR##uart_##L = ((F_CPU / 16 + baud / 2) / baud - 1); \
|
||||
\
|
||||
/* reset config for UART */ \
|
||||
UCSR##uart_##A = 0; \
|
||||
UCSR##uart_##B = 0; \
|
||||
UCSR##uart_##C = 0; \
|
||||
\
|
||||
/* enable rx and tx */ \
|
||||
sbi(UCSR##uart_##B, RXEN##uart_);\
|
||||
sbi(UCSR##uart_##B, TXEN##uart_);\
|
||||
\
|
||||
/* enable interrupt on complete reception of a byte */ \
|
||||
sbi(UCSR##uart_##B, RXCIE##uart_); \
|
||||
UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
|
||||
/* defaults to 8-bit, no parity, 1 stop bit */ \
|
||||
}
|
||||
|
||||
void beginSerial(uint8_t uart, long baud)
|
||||
{
|
||||
if (uart == 0) BEGIN_SERIAL(0, baud)
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
else BEGIN_SERIAL(1, baud)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SERIAL_WRITE(uart_, c_) \
|
||||
while (!(UCSR##uart_##A & (1 << UDRE##uart_))) \
|
||||
; \
|
||||
UDR##uart_ = c
|
||||
|
||||
void serialWrite(uint8_t uart, unsigned char c)
|
||||
{
|
||||
if (uart == 0) {
|
||||
SERIAL_WRITE(0, c);
|
||||
}
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
else {
|
||||
SERIAL_WRITE(1, c);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int serialAvailable(uint8_t uart)
|
||||
{
|
||||
return (RX_BUFFER_SIZE + rx_buffer_head[uart] - rx_buffer_tail[uart]) & RX_BUFFER_MASK;
|
||||
}
|
||||
|
||||
int serialRead(uint8_t uart)
|
||||
{
|
||||
// if the head isn't ahead of the tail, we don't have any characters
|
||||
if (rx_buffer_head[uart] == rx_buffer_tail[uart]) {
|
||||
return -1;
|
||||
} else {
|
||||
unsigned char c = rx_buffer[uart][rx_buffer_tail[uart]];
|
||||
rx_buffer_tail[uart] = (rx_buffer_tail[uart] + 1) & RX_BUFFER_MASK;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
void serialFlush(uint8_t uart)
|
||||
{
|
||||
// don't reverse this or there may be problems if the RX interrupt
|
||||
// occurs after reading the value of rx_buffer_head but before writing
|
||||
// the value to rx_buffer_tail; the previous value of rx_buffer_head
|
||||
// may be written to rx_buffer_tail, making it appear as if the buffer
|
||||
// were full, not empty.
|
||||
rx_buffer_head[uart] = rx_buffer_tail[uart];
|
||||
}
|
||||
|
||||
#define UART_ISR(uart_) \
|
||||
ISR(USART##uart_##_RX_vect) \
|
||||
{ \
|
||||
unsigned char c = UDR##uart_; \
|
||||
\
|
||||
int i = (rx_buffer_head[uart_] + 1) & RX_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 != rx_buffer_tail[uart_]) { \
|
||||
rx_buffer[uart_][rx_buffer_head[uart_]] = c; \
|
||||
rx_buffer_head[uart_] = i; \
|
||||
} \
|
||||
}
|
||||
|
||||
UART_ISR(0)
|
||||
#if defined(__AVR_ATmega644P__)
|
||||
UART_ISR(1)
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
#include "z_probe.h"
|
||||
#if defined(PROBE_PIN) && (PROBE_PIN > -1)
|
||||
#include "Marlin.h"
|
||||
#include "stepper.h"
|
||||
#include "temperature.h"
|
||||
|
||||
float Probe_Bed(float x_pos, float y_pos, int n)
|
||||
{
|
||||
//returns Probed Z average height
|
||||
float ProbeDepth[n];
|
||||
float ProbeDepthAvg=0;
|
||||
|
||||
//force bed heater off for probing
|
||||
int save_bed_targ = target_raw_bed;
|
||||
target_raw_bed = 0;
|
||||
WRITE(HEATER_BED_PIN,LOW);
|
||||
|
||||
if (Z_HOME_DIR==-1)
|
||||
{
|
||||
//int probe_flag =1;
|
||||
float meas = 0;
|
||||
int fails = 0;
|
||||
saved_feedrate = feedrate;
|
||||
saved_feedmultiply = feedmultiply;
|
||||
feedmultiply = 100;
|
||||
//previous_millis_cmd = millis();
|
||||
|
||||
//Move to probe position
|
||||
if (x_pos >= 0) destination[X_AXIS]=x_pos;
|
||||
if (y_pos >= 0) destination[Y_AXIS]=y_pos;
|
||||
//destination[Z_AXIS]=current_position[Z_AXIS];
|
||||
destination[Z_AXIS]=Z_HOME_RETRACT_MM;
|
||||
feedrate = 9000;
|
||||
prepare_move();
|
||||
|
||||
enable_endstops(true);
|
||||
SERIAL_ECHO("PRE-PROBE current_position[Z_AXIS]=");SERIAL_ECHOLN(current_position[Z_AXIS]);
|
||||
|
||||
SERIAL_ECHOLN("Ready to probe...");
|
||||
|
||||
//Probe bed n times
|
||||
//*******************************************************************************************Bed Loop*************************************
|
||||
for(int8_t i=0; i < n ; i++)
|
||||
{
|
||||
//int z = 0;
|
||||
|
||||
//fast probe
|
||||
//plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
||||
destination[Z_AXIS] = 1.1 * Z_MAX_LENGTH * Z_HOME_DIR;
|
||||
feedrate = homing_feedrate[Z_AXIS];
|
||||
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
|
||||
st_synchronize();
|
||||
|
||||
//feedrate = 0.0;
|
||||
|
||||
SERIAL_ECHO("current_position[Z_AXIS]=");SERIAL_ECHOLN(current_position[Z_AXIS]);
|
||||
if(endstop_z_hit == true)
|
||||
{
|
||||
SERIAL_ECHO("endstops_trigsteps[Z_AXIS]=");SERIAL_ECHOLN(endstops_trigsteps[Z_AXIS]);
|
||||
ProbeDepth[i]= endstops_trigsteps[Z_AXIS] / axis_steps_per_unit[Z_AXIS];
|
||||
meas = ProbeDepth[i];
|
||||
SERIAL_ECHO("ProbeDepth[");SERIAL_ECHO(i);SERIAL_ECHO("]=");SERIAL_ECHOLN(ProbeDepth[i]);
|
||||
//*************************************************************************************************************
|
||||
if (i > 0 ) //Second probe has happened so compare results
|
||||
{
|
||||
if (abs(ProbeDepth[i] - ProbeDepth[i - 1]) > .05)
|
||||
{ //keep going until readings match to avoid sticky bed
|
||||
SERIAL_ECHO("Probing again: ");
|
||||
SERIAL_ECHO(ProbeDepth[i]); SERIAL_ECHO(" - "); SERIAL_ECHO(ProbeDepth[i - 1]);SERIAL_ECHO(" = "); SERIAL_ECHOLN(abs(ProbeDepth[i] - ProbeDepth[i - 1]));
|
||||
meas = ProbeDepth[i];
|
||||
i--; i--; //Throw out both that don't match because we don't know which one is accurate
|
||||
if(fails++ > 4) break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
SERIAL_ECHOLN("Probe not triggered.");
|
||||
i=n-1;
|
||||
}
|
||||
//**************************************************************************************************************************************************
|
||||
//fast move clear
|
||||
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], meas, current_position[E_AXIS]);
|
||||
destination[Z_AXIS] = Z_HOME_RETRACT_MM;
|
||||
feedrate = fast_home_feedrate[Z_AXIS];
|
||||
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
|
||||
st_synchronize();
|
||||
|
||||
//check z stop isn't still triggered
|
||||
if ( READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING )
|
||||
{
|
||||
SERIAL_ECHOLN("Poking Stuck Bed:");
|
||||
destination[Z_AXIS] = -1; prepare_move();
|
||||
destination[Z_AXIS] = Z_HOME_RETRACT_MM; prepare_move();
|
||||
st_synchronize();
|
||||
i--; //Throw out this meaningless measurement
|
||||
}
|
||||
feedrate = 0;
|
||||
} //end probe loop
|
||||
#ifdef ENDSTOPS_ONLY_FOR_HOMING
|
||||
enable_endstops(false);
|
||||
#endif
|
||||
|
||||
feedrate = saved_feedrate;
|
||||
feedmultiply = saved_feedmultiply;
|
||||
//previous_millis_cmd = millis();
|
||||
endstops_hit_on_purpose();
|
||||
}
|
||||
for(int8_t i=0;i<n;i++)
|
||||
{
|
||||
ProbeDepthAvg += ProbeDepth[i];
|
||||
}
|
||||
ProbeDepthAvg /= n;
|
||||
SERIAL_ECHO("Probed Z="); SERIAL_ECHOLN(ProbeDepthAvg);
|
||||
SERIAL_ECHO("RAW current_position[Z_AXIS]=");SERIAL_ECHOLN(current_position[Z_AXIS]);
|
||||
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], Z_HOME_RETRACT_MM, current_position[E_AXIS]);
|
||||
current_position[Z_AXIS] = Z_HOME_RETRACT_MM;
|
||||
|
||||
target_raw_bed = save_bed_targ;
|
||||
return ProbeDepthAvg;
|
||||
}
|
||||
|
||||
void probe_init()
|
||||
{
|
||||
SET_INPUT(PROBE_PIN);
|
||||
WRITE(PROBE_PIN,HIGH);
|
||||
}
|
||||
|
||||
/*Crash1 - G29 to Probe and stop on Bed
|
||||
G29 will probe bed at least twice at 3 points and take an average. G30 will probe bed at it's current location.
|
||||
Z stop should be set slightly below bed height. Solder stub wire to each hole in huxley bed and attach a ring terminal under spring.
|
||||
Wire bed probe to A2 on Melzi and duplicate cap/resistor circuit in schematic.
|
||||
|
||||
Use something like this in the start.gcode file:
|
||||
G29 ;Probe bed for Z height
|
||||
G92 Z0 ;Set Z to Probed Depth
|
||||
G1 Z5 F200 ;Lift Z out of way
|
||||
*/
|
||||
void probe_3points()
|
||||
{
|
||||
float Probe_Avg, Point1, Point2, Point3;
|
||||
Point1 = Probe_Bed(15,15,PROBE_N);
|
||||
Point2 = Probe_Bed(X_MAX_LENGTH - 20,15,PROBE_N) ;
|
||||
Point3 = Probe_Bed(X_MAX_LENGTH/2,Y_MAX_LENGTH - 5,PROBE_N);
|
||||
Probe_Avg = (Point1 + Point2 + Point3) / 3;
|
||||
//destination[2] = Probe_Avg;
|
||||
//feedrate = homing_feedrate[Z_AXIS];
|
||||
//prepare_move();
|
||||
SERIAL_ECHOLN("**************************************");
|
||||
SERIAL_ECHO("Point1 ="); SERIAL_ECHOLN(Point1);
|
||||
SERIAL_ECHO("Point2 ="); SERIAL_ECHOLN(Point2);
|
||||
SERIAL_ECHO("Point3 ="); SERIAL_ECHOLN(Point3);
|
||||
SERIAL_ECHO("Probed Average="); SERIAL_ECHOLN(Probe_Avg);
|
||||
SERIAL_ECHOLN("**************************************");
|
||||
}
|
||||
|
||||
void probe_1point()
|
||||
{
|
||||
float Point;
|
||||
Point = Probe_Bed(-1,-1,PROBE_N);
|
||||
//destination[2] = Point +1;
|
||||
//feedrate = homing_feedrate[Z_AXIS];
|
||||
//prepare_move();
|
||||
SERIAL_ECHOLN("**************************************");
|
||||
SERIAL_ECHO("Probed Z="); SERIAL_ECHOLN(Point);
|
||||
}
|
||||
|
||||
void probe_status()
|
||||
{
|
||||
SERIAL_ECHO("Probe Status = "); SERIAL_ECHOLN(READ(PROBE_PIN));
|
||||
}
|
||||
|
||||
#endif //defined(PROBE_PIN) > -1
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __Z_PROBEH
|
||||
|
||||
#define __Z_PROBEH
|
||||
#include "Marlin.h"
|
||||
|
||||
#if defined(PROBE_PIN) && (PROBE_PIN > -1)
|
||||
void probe_init();
|
||||
void probe_3points();
|
||||
void probe_1point();
|
||||
void probe_status();
|
||||
float Probe_Bed(float x_pos, float y_pos,int n);
|
||||
|
||||
#else //no probe pin
|
||||
FORCE_INLINE void probe_init() {};
|
||||
FORCE_INLINE void probe_3points() {};
|
||||
FORCE_INLINE void probe_1point() {};
|
||||
FORCE_INLINE void probe_status() {};
|
||||
FORCE_INLINE float Probe_Bed(float x_pos, float y_pos,int n) {return 0;}
|
||||
#endif //PROBE_PIN
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
A new beta version is avaiable.
|
||||
Look under the Marlin_v1 branch. We also made a tag that you can download.
|
||||
|
||||
@@ -85,3 +86,69 @@ The best workaround is to move these files to sanguino directory.
|
||||
|
||||
|
||||
|
||||
=======
|
||||
This RepRap firmware is a mashup between Sprinter, grbl and many original parts.
|
||||
(https://github.com/kliment/Sprinter)
|
||||
(https://github.com/simen/grbl/tree)
|
||||
|
||||
Derived from Sprinter and Grbl by Erik van der Zalm.
|
||||
Sprinters lead developers are Kliment and caru.
|
||||
Grbls lead developer is Simen Svale Skogsrud.
|
||||
It has been adapted to the Ultimaker Printer by:
|
||||
Bernhard Kubicek, Matthijs Keuper, Bradley Feldman, and others...
|
||||
|
||||
|
||||
Features:
|
||||
- Interrupt based movement with real linear acceleration
|
||||
- High steprate
|
||||
- Look ahead (Keep the speed high when possible. High cornering speed)
|
||||
- Interrupt based temperature protection
|
||||
- preliminary support for Matthew Roberts advance algorithm
|
||||
For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
|
||||
- Full endstop support
|
||||
- Simple LCD support (16x2)
|
||||
- SD Card support
|
||||
- Provisions for Bernhard Kubicek's new hardware control console and 20x4 lcd
|
||||
|
||||
This firmware is optimized for Ultimaker's gen6 electronics (including the Ultimaker 1.5.x daughterboard and Arduino Mega 2560).
|
||||
|
||||
The default baudrate is 115200.
|
||||
|
||||
|
||||
========================================================================================
|
||||
|
||||
Configuring and compilation
|
||||
|
||||
|
||||
Install the latest arduino software IDE/toolset (currently 0022)
|
||||
http://www.arduino.cc/en/Main/Software
|
||||
|
||||
Install Ultimaker's RepG 25 build
|
||||
http://software.ultimaker.com
|
||||
(or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_)
|
||||
|
||||
Copy the Ultimaker Marlin firmware
|
||||
https:/github.com/bkubicek/Marlin
|
||||
(Use the download button)
|
||||
|
||||
Start the arduino IDE.
|
||||
Select Tools -> Board -> Arduino Mega 2560
|
||||
Select the correct serial port in Tools ->Serial Port
|
||||
Open Marlin.pde
|
||||
|
||||
Click the Verify/Compile button
|
||||
|
||||
Click the Upload button
|
||||
If all goes well the firmware is uploading
|
||||
|
||||
Start Ultimaker's Custom RepG 25
|
||||
Make sure Show Experimental Profiles is enabled in Preferences
|
||||
Select Sprinter as the Driver
|
||||
|
||||
Press the Connect button.
|
||||
|
||||
KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z
|
||||
|
||||
That's ok. Enjoy Silky Smooth Printing.
|
||||
|
||||
>>>>>>> Mendel
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
WARNING:
|
||||
--------
|
||||
THIS IS RELEASE CANDIDATE 1 FOR MARLIN 1.0.0
|
||||
|
||||
The configuration is now split in two files
|
||||
Configuration.h for the normal settings
|
||||
Configuration_adv.h for the advanced settings
|
||||
|
||||
Quick Information
|
||||
===================
|
||||
This RepRap firmware is a mashup between <a href="https://github.com/kliment/Sprinter">Sprinter</a>, <a href="https://github.com/simen/grbl/tree">grbl</a> and many original parts.
|
||||
|
||||
Derived from Sprinter and Grbl by Erik van der Zalm.
|
||||
Sprinters lead developers are Kliment and caru.
|
||||
Grbls lead developer is Simen Svale Skogsrud. Sonney Jeon (Chamnit) improved some parts of grbl
|
||||
A fork by bkubicek for the Ultimaker was merged, and further development was aided by him.
|
||||
Some features have been added by:
|
||||
Lampmaker, Bradley Feldman, and others...
|
||||
|
||||
|
||||
Features:
|
||||
|
||||
* Interrupt based movement with real linear acceleration
|
||||
* High steprate
|
||||
* Look ahead (Keep the speed high when possible. High cornering speed)
|
||||
* Interrupt based temperature protection
|
||||
* preliminary support for Matthew Roberts advance algorithm
|
||||
For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
|
||||
* Full endstop support
|
||||
* SD Card support
|
||||
* SD Card folders (works in pronterface)
|
||||
* LCD support (ideally 20x4)
|
||||
* LCD menu system for autonomous SD card printing, controlled by an click-encoder.
|
||||
* EEPROM storage of e.g. max-velocity, max-acceleration, and similar variables
|
||||
* many small but handy things originating from bkubicek's fork.
|
||||
* Arc support
|
||||
* Temperature oversampling
|
||||
* Dynamic Temperature setpointing aka "AutoTemp"
|
||||
* Support for QTMarlin, a very beta GUI for PID-tuning and velocity-acceleration testing. https://github.com/bkubicek/QTMarlin
|
||||
* Endstop trigger reporting to the host software.
|
||||
* Updated sdcardlib
|
||||
* Heater power reporting. Useful for PID monitoring.
|
||||
|
||||
The default baudrate is 250000. This baudrate has less jitter and hence errors than the usual 115200 baud, but is less supported by drivers and host-environments.
|
||||
|
||||
|
||||
Differences and additions to the already good Sprinter firmware:
|
||||
================================================================
|
||||
|
||||
*Look-ahead:*
|
||||
|
||||
Marlin has look-ahead. While sprinter has to break and re-accelerate at each corner,
|
||||
lookahead will only decelerate and accelerate to a velocity,
|
||||
so that the change in vectorial velocity magnitude is less than the xy_jerk_velocity.
|
||||
This is only possible, if some future moves are already processed, hence the name.
|
||||
It leads to less over-deposition at corners, especially at flat angles.
|
||||
|
||||
*Arc support:*
|
||||
|
||||
Slic3r can find curves that, although broken into segments, were ment to describe an arc.
|
||||
Marlin is able to print those arcs. The advantage is the firmware can choose the resolution,
|
||||
and can perform the arc with nearly constant velocity, resulting in a nice finish.
|
||||
Also, less serial communication is needed.
|
||||
|
||||
*Temperature Oversampling:*
|
||||
|
||||
To reduce noise and make the PID-differential term more useful, 16 ADC conversion results are averaged.
|
||||
|
||||
*AutoTemp:*
|
||||
|
||||
If your gcode contains a wide spread of extruder velocities, or you realtime change the building speed, the temperature should be changed accordingly.
|
||||
Usually, higher speed requires higher temperature.
|
||||
This can now be performed by the AutoTemp function
|
||||
By calling M109 S<mintemp> T<maxtemp> F<factor> you enter the autotemp mode.
|
||||
|
||||
You can leave it by calling M109 without any F.
|
||||
If active, the maximal extruder stepper rate of all buffered moves will be calculated, and named "maxerate" [steps/sec].
|
||||
The wanted temperature then will be set to t=tempmin+factor*maxerate, while being limited between tempmin and tempmax.
|
||||
If the target temperature is set manually or by gcode to a value less then tempmin, it will be kept without change.
|
||||
Ideally, your gcode can be completely free of temperature controls, apart from a M109 S T F in the start.gcode, and a M109 S0 in the end.gcode.
|
||||
|
||||
*EEPROM:*
|
||||
|
||||
If you know your PID values, the acceleration and max-velocities of your unique machine, you can set them, and finally store them in the EEPROM.
|
||||
After each reboot, it will magically load them from EEPROM, independent what your Configuration.h says.
|
||||
|
||||
*LCD Menu:*
|
||||
|
||||
If your hardware supports it, you can build yourself a LCD-CardReader+Click+encoder combination. It will enable you to realtime tune temperatures,
|
||||
accelerations, velocities, flow rates, select and print files from the SD card, preheat, disable the steppers, and do other fancy stuff.
|
||||
One working hardware is documented here: http://www.thingiverse.com/thing:12663
|
||||
Also, with just a 20x4 or 16x2 display, useful data is shown.
|
||||
|
||||
*SD card folders:*
|
||||
|
||||
If you have an SD card reader attached to your controller, also folders work now. Listing the files in pronterface will show "/path/subpath/file.g".
|
||||
You can write to file in a subfolder by specifying a similar text using small letters in the path.
|
||||
Also, backup copies of various operating systems are hidden, as well as files not ending with ".g".
|
||||
|
||||
*Endstop trigger reporting:*
|
||||
|
||||
If an endstop is hit while moving towards the endstop, the location at which the firmware thinks that the endstop was triggered is outputed on the serial port.
|
||||
This is useful, because the user gets a warning message.
|
||||
However, also tools like QTMarlin can use this for finding acceptable combinations of velocity+acceleration.
|
||||
|
||||
*Coding paradigm:*
|
||||
|
||||
Not relevant from a user side, but Marlin was split into thematic junks, and has tried to partially enforced private variables.
|
||||
This is intended to make it clearer, what interacts which what, and leads to a higher level of modularization.
|
||||
We think that this is a useful prestep for porting this firmware to e.g. an ARM platform in the future.
|
||||
A lot of RAM (with enabled LCD ~2200 bytes) was saved by storing char []="some message" in Program memory.
|
||||
In the serial communication, a #define based level of abstraction was enforced, so that it is clear that
|
||||
some transfer is information (usually beginning with "echo:"), an error "error:", or just normal protocol,
|
||||
necessary for backwards compatibility.
|
||||
|
||||
*Interrupt based temperature measurements:*
|
||||
|
||||
An interrupt is used to manage ADC conversions, and enforce checking for critical temperatures.
|
||||
This leads to less blocking in the heater management routine.
|
||||
|
||||
|
||||
Non-standard M-Codes, different to an old version of sprinter:
|
||||
==============================================================
|
||||
Movement:
|
||||
|
||||
* G2 - CW ARC
|
||||
* G3 - CCW ARC
|
||||
|
||||
General:
|
||||
|
||||
* M17 - Enable/Power all stepper motors. Compatibility to ReplicatorG.
|
||||
* M18 - Disable all stepper motors; same as M84.Compatibility to ReplicatorG.
|
||||
* M30 - Print time since last M109 or SD card start to serial
|
||||
* M42 - Change pin status via gcode
|
||||
* M80 - Turn on Power Supply
|
||||
* M81 - Turn off Power Supply
|
||||
* M114 - Output current position to serial port
|
||||
* M119 - Output Endstop status to serial port
|
||||
|
||||
Movement variables:
|
||||
|
||||
* M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
|
||||
* M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
|
||||
* M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate
|
||||
* M220 - set build speed mulitplying S:factor in percent ; aka "realtime tuneing in the gcode". So you can slow down if you have islands in one height-range, and speed up otherwise.
|
||||
* M301 - Set PID parameters P I and D
|
||||
* M400 - Finish all buffered moves.
|
||||
|
||||
Advance:
|
||||
|
||||
* M200 - Set filament diameter for advance
|
||||
* M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
|
||||
|
||||
EEPROM:
|
||||
|
||||
* M500 - stores paramters in EEPROM
|
||||
* M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
|
||||
* M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
|
||||
|
||||
|
||||
Configuring and compilation:
|
||||
============================
|
||||
|
||||
Install the arduino software IDE/toolset v22
|
||||
http://www.arduino.cc/en/Main/Software
|
||||
|
||||
For gen6 and sanguinololu the Sanguino directory in the Marlin dir needs to be copied to the arduino environment.
|
||||
copy Marlin\sanguino <arduino home>\hardware\Sanguino
|
||||
|
||||
Install Ultimaker's RepG 25 build
|
||||
http://software.ultimaker.com
|
||||
For SD handling and as better substitute (apart from stl manipulation) download
|
||||
the very nice Kliment's printrun/pronterface https://github.com/kliment/Printrun
|
||||
|
||||
Copy the Ultimaker Marlin firmware
|
||||
https://github.com/ErikZalm/Marlin/tree/Marlin_v1
|
||||
(Use the download button)
|
||||
|
||||
Start the arduino IDE.
|
||||
Select Tools -> Board -> Arduino Mega 2560 or your microcontroller
|
||||
Select the correct serial port in Tools ->Serial Port
|
||||
Open Marlin.pde
|
||||
|
||||
Click the Verify/Compile button
|
||||
|
||||
Click the Upload button
|
||||
If all goes well the firmware is uploading
|
||||
|
||||
Start Ultimaker's Custom RepG 25
|
||||
Make sure Show Experimental Profiles is enabled in Preferences
|
||||
Select Sprinter as the Driver
|
||||
|
||||
Press the Connect button.
|
||||
|
||||
KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z
|
||||
|
||||
That's ok. Enjoy Silky Smooth Printing.
|
||||
|
||||
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
<<<<<<< HEAD
|
||||
A new beta version is avaiable.
|
||||
Look under the Marlin_v1 branch. We also made a tag that you can download.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This firmware is a mashup between Sprinter, grbl and many original parts.
|
||||
(https://github.com/kliment/Sprinter)
|
||||
(https://github.com/simen/grbl/tree)
|
||||
|
||||
Features:
|
||||
- Interrupt based movement with real linear acceleration
|
||||
- High steprate
|
||||
- Look ahead (Keep the speed high when possible. High cornering speed)
|
||||
- Interrupt based temperature protection
|
||||
- preliminary support for Matthew Roberts advance algorithm
|
||||
For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
|
||||
|
||||
This firmware is optimized for gen6 electronics.
|
||||
|
||||
The default baudrate is 250000.
|
||||
This gives less communication errors then regular baudrates.
|
||||
|
||||
========================================================================================
|
||||
|
||||
Configuring and compilation
|
||||
|
||||
|
||||
Install the arduino software version 0018
|
||||
http://www.arduino.cc/en/Main/Software
|
||||
|
||||
Install the sanguino software, version 0018
|
||||
http://sanguino.cc/useit
|
||||
|
||||
Install pronterface
|
||||
https://github.com/kliment/Printrun
|
||||
|
||||
Copy the Marlin firmware
|
||||
https:/github.com/ErikZalm/Marlin
|
||||
(Use the download button)
|
||||
|
||||
Start the arduino IDE.
|
||||
Select Tools -> Board -> Sanguino
|
||||
Select the correct serial port in Tools ->Serial Port
|
||||
Open Marlin.pde
|
||||
|
||||
Change the printer specific setting in Configuration.h to the correct values.
|
||||
|
||||
The following values are the most important:
|
||||
- float axis_steps_per_unit[].... // Set the correct steps / mm in the corresponding field
|
||||
- const bool ENDSTOPS_INVERTING = false; // Change if only positive moves are executed
|
||||
- #define INVERT_x_DIR true // Change if the motor direction is wrong
|
||||
|
||||
Click the Upload button
|
||||
If all goes well the firmware is uploading
|
||||
|
||||
Start pronterface
|
||||
|
||||
Select the correct Serial Port. Type 250000 in the baudrate field.
|
||||
Press the Connect button
|
||||
|
||||
===============================================================================================
|
||||
Known issues
|
||||
|
||||
On some systems we get compilation errors.
|
||||
|
||||
This is caused by the "wiring_serial.c" and "wiring.c".
|
||||
The simple fix is to delete these files but this may have a performance impact.
|
||||
|
||||
The best workaround is to move these files to sanguino directory.
|
||||
(".../arduino-0018/hardware/Sanguino/cores/arduino/" on windows systems)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
=======
|
||||
This RepRap firmware is a mashup between Sprinter, grbl and many original parts.
|
||||
(https://github.com/kliment/Sprinter)
|
||||
(https://github.com/simen/grbl/tree)
|
||||
|
||||
Derived from Sprinter and Grbl by Erik van der Zalm.
|
||||
Sprinters lead developers are Kliment and caru.
|
||||
Grbls lead developer is Simen Svale Skogsrud.
|
||||
It has been adapted to the Ultimaker Printer by:
|
||||
Bernhard Kubicek, Matthijs Keuper, Bradley Feldman, and others...
|
||||
|
||||
|
||||
Features:
|
||||
- Interrupt based movement with real linear acceleration
|
||||
- High steprate
|
||||
- Look ahead (Keep the speed high when possible. High cornering speed)
|
||||
- Interrupt based temperature protection
|
||||
- preliminary support for Matthew Roberts advance algorithm
|
||||
For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
|
||||
- Full endstop support
|
||||
- Simple LCD support (16x2)
|
||||
- SD Card support
|
||||
- Provisions for Bernhard Kubicek's new hardware control console and 20x4 lcd
|
||||
|
||||
This firmware is optimized for Ultimaker's gen6 electronics (including the Ultimaker 1.5.x daughterboard and Arduino Mega 2560).
|
||||
|
||||
The default baudrate is 115200.
|
||||
|
||||
|
||||
========================================================================================
|
||||
|
||||
Configuring and compilation
|
||||
|
||||
|
||||
Install the latest arduino software IDE/toolset (currently 0022)
|
||||
http://www.arduino.cc/en/Main/Software
|
||||
|
||||
Install Ultimaker's RepG 25 build
|
||||
http://software.ultimaker.com
|
||||
(or alternatively install Kliment's printrun/pronterface https://github.com/kliment/Printrun_)
|
||||
|
||||
Copy the Ultimaker Marlin firmware
|
||||
https:/github.com/bkubicek/Marlin
|
||||
(Use the download button)
|
||||
|
||||
Start the arduino IDE.
|
||||
Select Tools -> Board -> Arduino Mega 2560
|
||||
Select the correct serial port in Tools ->Serial Port
|
||||
Open Marlin.pde
|
||||
|
||||
Click the Verify/Compile button
|
||||
|
||||
Click the Upload button
|
||||
If all goes well the firmware is uploading
|
||||
|
||||
Start Ultimaker's Custom RepG 25
|
||||
Make sure Show Experimental Profiles is enabled in Preferences
|
||||
Select Sprinter as the Driver
|
||||
|
||||
Press the Connect button.
|
||||
|
||||
KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z
|
||||
|
||||
That's ok. Enjoy Silky Smooth Printing.
|
||||
|
||||
>>>>>>> Mendel
|
||||
Reference in New Issue
Block a user