From e4af5e82f26fab59bb2bda540e1673317f48ce8a Mon Sep 17 00:00:00 2001 From: kliment Date: Mon, 4 Jul 2011 16:17:19 +0200 Subject: Rename to Sprinter --- Sprinter/BedThermistorTable_100k.h | 85 ++ Sprinter/BedThermistorTable_200k.h | 42 + Sprinter/FatStructs.h | 418 +++++++ Sprinter/Makefile | 247 ++++ Sprinter/Sd2Card.cpp | 643 ++++++++++ Sprinter/Sd2Card.h | 233 ++++ Sprinter/Sd2PinMap.h | 353 ++++++ Sprinter/SdFat.h | 547 +++++++++ Sprinter/SdFatUtil.h | 70 ++ Sprinter/SdFatmainpage.h | 202 ++++ Sprinter/SdFile.cpp | 1252 +++++++++++++++++++ Sprinter/SdInfo.h | 232 ++++ Sprinter/SdVolume.cpp | 295 +++++ Sprinter/Sprinter.h | 36 + Sprinter/Sprinter.pde | 1548 ++++++++++++++++++++++++ Sprinter/ThermistorTable_100k.h | 85 ++ Sprinter/ThermistorTable_200k.h | 42 + Sprinter/ThermistorTable_mendelparts.h | 45 + Sprinter/configuration.h | 158 +++ Sprinter/createTemperatureLookup.py | 127 ++ Sprinter/pins.h | 477 ++++++++ Tonokip_Firmware/BedThermistorTable_100k.h | 85 -- Tonokip_Firmware/BedThermistorTable_200k.h | 42 - Tonokip_Firmware/FatStructs.h | 418 ------- Tonokip_Firmware/Makefile | 247 ---- Tonokip_Firmware/Sd2Card.cpp | 643 ---------- Tonokip_Firmware/Sd2Card.h | 233 ---- Tonokip_Firmware/Sd2PinMap.h | 353 ------ Tonokip_Firmware/SdFat.h | 547 --------- Tonokip_Firmware/SdFatUtil.h | 70 -- Tonokip_Firmware/SdFatmainpage.h | 202 ---- Tonokip_Firmware/SdFile.cpp | 1252 ------------------- Tonokip_Firmware/SdInfo.h | 232 ---- Tonokip_Firmware/SdVolume.cpp | 295 ----- Tonokip_Firmware/ThermistorTable_100k.h | 85 -- Tonokip_Firmware/ThermistorTable_200k.h | 42 - Tonokip_Firmware/ThermistorTable_mendelparts.h | 45 - Tonokip_Firmware/Tonokip_Firmware.h | 36 - Tonokip_Firmware/Tonokip_Firmware.pde | 1548 ------------------------ Tonokip_Firmware/configuration.h | 158 --- Tonokip_Firmware/createTemperatureLookup.py | 127 -- Tonokip_Firmware/pins.h | 477 -------- 42 files changed, 7137 insertions(+), 7137 deletions(-) create mode 100644 Sprinter/BedThermistorTable_100k.h create mode 100644 Sprinter/BedThermistorTable_200k.h create mode 100644 Sprinter/FatStructs.h create mode 100644 Sprinter/Makefile create mode 100644 Sprinter/Sd2Card.cpp create mode 100644 Sprinter/Sd2Card.h create mode 100644 Sprinter/Sd2PinMap.h create mode 100644 Sprinter/SdFat.h create mode 100644 Sprinter/SdFatUtil.h create mode 100644 Sprinter/SdFatmainpage.h create mode 100644 Sprinter/SdFile.cpp create mode 100644 Sprinter/SdInfo.h create mode 100644 Sprinter/SdVolume.cpp create mode 100644 Sprinter/Sprinter.h create mode 100644 Sprinter/Sprinter.pde create mode 100644 Sprinter/ThermistorTable_100k.h create mode 100644 Sprinter/ThermistorTable_200k.h create mode 100644 Sprinter/ThermistorTable_mendelparts.h create mode 100644 Sprinter/configuration.h create mode 100644 Sprinter/createTemperatureLookup.py create mode 100644 Sprinter/pins.h delete mode 100644 Tonokip_Firmware/BedThermistorTable_100k.h delete mode 100644 Tonokip_Firmware/BedThermistorTable_200k.h delete mode 100644 Tonokip_Firmware/FatStructs.h delete mode 100644 Tonokip_Firmware/Makefile delete mode 100644 Tonokip_Firmware/Sd2Card.cpp delete mode 100644 Tonokip_Firmware/Sd2Card.h delete mode 100644 Tonokip_Firmware/Sd2PinMap.h delete mode 100644 Tonokip_Firmware/SdFat.h delete mode 100644 Tonokip_Firmware/SdFatUtil.h delete mode 100644 Tonokip_Firmware/SdFatmainpage.h delete mode 100644 Tonokip_Firmware/SdFile.cpp delete mode 100644 Tonokip_Firmware/SdInfo.h delete mode 100644 Tonokip_Firmware/SdVolume.cpp delete mode 100644 Tonokip_Firmware/ThermistorTable_100k.h delete mode 100644 Tonokip_Firmware/ThermistorTable_200k.h delete mode 100644 Tonokip_Firmware/ThermistorTable_mendelparts.h delete mode 100644 Tonokip_Firmware/Tonokip_Firmware.h delete mode 100644 Tonokip_Firmware/Tonokip_Firmware.pde delete mode 100644 Tonokip_Firmware/configuration.h delete mode 100644 Tonokip_Firmware/createTemperatureLookup.py delete mode 100644 Tonokip_Firmware/pins.h diff --git a/Sprinter/BedThermistorTable_100k.h b/Sprinter/BedThermistorTable_100k.h new file mode 100644 index 0000000..84bc607 --- /dev/null +++ b/Sprinter/BedThermistorTable_100k.h @@ -0,0 +1,85 @@ +#ifndef THERMISTORTABLE_H_ +#define THERMISTORTABLE_H_ + +// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) +// See this page: +// http://dev.www.reprap.org/bin/view/Main/Thermistor +// for details of what goes in this table. +// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 + +#define BNUMTEMPS 61 +const short bedtemptable[BNUMTEMPS][2] = { +{ 23 , 300 }, +{ 25 , 295 }, +{ 27 , 290 }, +{ 28 , 285 }, +{ 31 , 280 }, +{ 33 , 275 }, +{ 35 , 270 }, +{ 38 , 265 }, +{ 41 , 260 }, +{ 44 , 255 }, +{ 48 , 250 }, +{ 52 , 245 }, +{ 56 , 240 }, +{ 61 , 235 }, +{ 66 , 230 }, +{ 71 , 225 }, +{ 78 , 220 }, +{ 84 , 215 }, +{ 92 , 210 }, +{ 100 , 205 }, +{ 109 , 200 }, +{ 120 , 195 }, +{ 131 , 190 }, +{ 143 , 185 }, +{ 156 , 180 }, +{ 171 , 175 }, +{ 187 , 170 }, +{ 205 , 165 }, +{ 224 , 160 }, +{ 245 , 155 }, +{ 268 , 150 }, +{ 293 , 145 }, +{ 320 , 140 }, +{ 348 , 135 }, +{ 379 , 130 }, +{ 411 , 125 }, +{ 445 , 120 }, +{ 480 , 115 }, +{ 516 , 110 }, +{ 553 , 105 }, +{ 591 , 100 }, +{ 628 , 95 }, +{ 665 , 90 }, +{ 702 , 85 }, +{ 737 , 80 }, +{ 770 , 75 }, +{ 801 , 70 }, +{ 830 , 65 }, +{ 857 , 60 }, +{ 881 , 55 }, +{ 903 , 50 }, +{ 922 , 45 }, +{ 939 , 40 }, +{ 954 , 35 }, +{ 966 , 30 }, +{ 977 , 25 }, +{ 985 , 20 }, +{ 993 , 15 }, +{ 999 , 10 }, +{ 1004 , 5 }, +{ 1008 , 0 }, + +}; + + +#endif + diff --git a/Sprinter/BedThermistorTable_200k.h b/Sprinter/BedThermistorTable_200k.h new file mode 100644 index 0000000..3d96aa3 --- /dev/null +++ b/Sprinter/BedThermistorTable_200k.h @@ -0,0 +1,42 @@ +#ifndef THERMISTORTABLE_H_ +#define THERMISTORTABLE_H_ + +// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) +// See this page: +// http://dev.www.reprap.org/bin/view/Main/Thermistor +// for details of what goes in this table. +// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 + +#define BNUMTEMPS 20 +const short bedtemptable[BNUMTEMPS][2] = { + {1, 848}, + {54, 275}, + {107, 228}, + {160, 202}, + {213, 185}, + {266, 171}, + {319, 160}, + {372, 150}, + {425, 141}, + {478, 133}, + {531, 125}, + {584, 118}, + {637, 110}, + {690, 103}, + {743, 95}, + {796, 86}, + {849, 77}, + {902, 65}, + {955, 49}, + {1008, 17} +}; + + +#endif diff --git a/Sprinter/FatStructs.h b/Sprinter/FatStructs.h new file mode 100644 index 0000000..f5bdaa5 --- /dev/null +++ b/Sprinter/FatStructs.h @@ -0,0 +1,418 @@ +/* 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 + * . + */ +#ifndef FatStructs_h +#define FatStructs_h +/** + * \file + * FAT file structures + */ +/* + * mostly from Microsoft document fatgen103.doc + * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx + */ +//------------------------------------------------------------------------------ +/** Value for byte 510 of boot block or MBR */ +uint8_t const BOOTSIG0 = 0X55; +/** Value for byte 511 of boot block or MBR */ +uint8_t const BOOTSIG1 = 0XAA; +//------------------------------------------------------------------------------ +/** + * \struct partitionTable + * \brief MBR partition table entry + * + * A partition table entry for a MBR formatted storage device. + * The MBR partition table has four entries. + */ +struct partitionTable { + /** + * Boot Indicator . Indicates whether the volume is the active + * partition. Legal values include: 0X00. Do not use for booting. + * 0X80 Active partition. + */ + uint8_t boot; + /** + * Head part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t beginHead; + /** + * Sector part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned beginSector : 6; + /** High bits cylinder for first block in partition. */ + unsigned beginCylinderHigh : 2; + /** + * Combine beginCylinderLow with beginCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t beginCylinderLow; + /** + * Partition type. See defines that begin with PART_TYPE_ for + * some Microsoft partition types. + */ + uint8_t type; + /** + * head part of cylinder-head-sector address of the last sector in the + * partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t endHead; + /** + * Sector part of cylinder-head-sector address of the last sector in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned endSector : 6; + /** High bits of end cylinder */ + unsigned endCylinderHigh : 2; + /** + * Combine endCylinderLow with endCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t endCylinderLow; + /** Logical block address of the first block in the partition. */ + uint32_t firstSector; + /** Length of the partition, in blocks. */ + uint32_t totalSectors; +}; +/** Type name for partitionTable */ +typedef struct partitionTable part_t; +//------------------------------------------------------------------------------ +/** + * \struct masterBootRecord + * + * \brief Master Boot Record + * + * The first block of a storage device that is formatted with a MBR. + */ +struct masterBootRecord { + /** Code Area for master boot program. */ + uint8_t codeArea[440]; + /** Optional WindowsNT disk signature. May contain more boot code. */ + uint32_t diskSignature; + /** Usually zero but may be more boot code. */ + uint16_t usuallyZero; + /** Partition tables. */ + part_t part[4]; + /** First MBR signature byte. Must be 0X55 */ + uint8_t mbrSig0; + /** Second MBR signature byte. Must be 0XAA */ + uint8_t mbrSig1; +}; +/** Type name for masterBootRecord */ +typedef struct masterBootRecord mbr_t; +//------------------------------------------------------------------------------ +/** + * \struct biosParmBlock + * + * \brief BIOS parameter block + * + * The BIOS parameter block describes the physical layout of a FAT volume. + */ +struct biosParmBlock { + /** + * Count of bytes per sector. This value may take on only the + * following values: 512, 1024, 2048 or 4096 + */ + 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. + */ + uint8_t sectorsPerCluster; + /** + * Number of sectors before the first FAT. + * This value must not be zero. + */ + 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. + */ + 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. + */ + 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 + * FAT12 and FAT16 volumes, this field contains the sector count, and + * totalSectors32 is 0 if the total sector count fits + * (is less than 0x10000). + */ + 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 (non-removable) media. For removable media, 0xF0 is + * frequently used. Legal values are 0xF0 or 0xF8-0xFF. + */ + uint8_t mediaType; + /** + * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. + * 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 sectorsPerTrtack; + /** 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; + /** + * 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. + */ + uint32_t totalSectors32; + /** + * Count of sectors occupied by one FAT on FAT32 volumes. + */ + uint32_t sectorsPerFat32; + /** + * This field is only defined for FAT32 media and does not exist on + * FAT12 and FAT16 media. + * Bits 0-3 -- Zero-based number of active FAT. + * 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. + * Bits 8-15 -- Reserved. + */ + uint16_t fat32Flags; + /** + * FAT32 version. High byte is major revision number. + * Low byte is minor revision number. Only 0.0 define. + */ + uint16_t fat32Version; + /** + * Cluster number of the first cluster of the root directory for FAT32. + * This usually 2 but not required to be 2. + */ + uint32_t fat32RootCluster; + /** + * Sector number of FSINFO structure in the reserved area of the + * FAT32 volume. Usually 1. + */ + uint16_t fat32FSInfo; + /** + * If non-zero, 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. + */ + uint16_t fat32BackBootBlock; + /** + * Reserved for future expansion. Code that formats FAT32 volumes + * 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 */ + 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 */ + uint32_t volumeSerialNumber; + /** should match volume label in root dir */ + char volumeLabel[11]; + /** informational only - don't depend on it */ + char fileSystemType[8]; + /** X86 boot code */ + uint8_t bootCode[420]; + /** must be 0X55 */ + uint8_t bootSectorSig0; + /** must be 0XAA */ + uint8_t bootSectorSig1; +}; +//------------------------------------------------------------------------------ +// End Of Chain values for FAT entries +/** FAT16 end of chain value used by Microsoft. */ +uint16_t const FAT16EOC = 0XFFFF; +/** Minimum value for FAT16 EOC. Use to test for EOC. */ +uint16_t const FAT16EOC_MIN = 0XFFF8; +/** FAT32 end of chain value used by Microsoft. */ +uint32_t const FAT32EOC = 0X0FFFFFFF; +/** Minimum value for FAT32 EOC. Use to test for EOC. */ +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 + * \brief FAT short directory entry + * + * Short means short 8.3 name, not the entry size. + * + * Date Format. A FAT directory entry date stamp is a 16-bit field that is + * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the + * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the + * 16-bit word): + * + * Bits 9-15: Count of years from 1980, valid value range 0-127 + * inclusive (1980-2107). + * + * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. + * + * Bits 0-4: Day of month, valid value range 1-31 inclusive. + * + * Time Format. A FAT directory entry time stamp is a 16-bit field that has + * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the + * 16-bit word, bit 15 is the MSB of the 16-bit word). + * + * Bits 11-15: Hours, valid value range 0-23 inclusive. + * + * Bits 5-10: Minutes, valid value range 0-59 inclusive. + * + * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). + * + * The valid time range is from Midnight 00:00:00 to 23:59:58. + */ +struct directoryEntry { + /** + * 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. + */ + uint8_t name[11]; + /** Entry attributes. + * + * The upper two bits of the attribute byte are reserved and should + * always be set to 0 when a file is created and never modified or + * looked at after that. See defines that begin with DIR_ATT_. + */ + uint8_t attributes; + /** + * Reserved for use by Windows NT. Set value to 0 when a file is + * created and never modify or look at it after that. + */ + uint8_t reservedNT; + /** + * The granularity of the seconds part of creationTime is 2 seconds + * so this field is a count of tenths of a second and its valid + * value range is 0-199 inclusive. (WHG note - seems to be hundredths) + */ + uint8_t creationTimeTenths; + /** Time file was created. */ + uint16_t creationTime; + /** Date file was created. */ + uint16_t creationDate; + /** + * Last access date. Note that there is no last access time, only + * a date. This is the date of last read or write. In the case of + * a write, this should be set to the same date as lastWriteDate. + */ + uint16_t lastAccessDate; + /** + * High word of this entry's first cluster number (always 0 for a + * FAT12 or FAT16 volume). + */ + uint16_t firstClusterHigh; + /** Time of last write. File creation is considered a write. */ + uint16_t lastWriteTime; + /** Date of last write. File creation is considered a write. */ + uint16_t lastWriteDate; + /** Low word of this entry's first cluster number. */ + uint16_t firstClusterLow; + /** 32-bit unsigned holding this file's size in bytes. */ + uint32_t fileSize; +}; +//------------------------------------------------------------------------------ +// Definitions for directory entries +// +/** Type name for directoryEntry */ +typedef struct directoryEntry dir_t; +/** escape for name[0] = 0XE5 */ +uint8_t const DIR_NAME_0XE5 = 0X05; +/** name[0] value for entry that is free after being "deleted" */ +uint8_t const DIR_NAME_DELETED = 0XE5; +/** name[0] value for entry that is free and no allocated entries follow */ +uint8_t const DIR_NAME_FREE = 0X00; +/** file is read-only */ +uint8_t const DIR_ATT_READ_ONLY = 0X01; +/** File should hidden in directory listings */ +uint8_t const DIR_ATT_HIDDEN = 0X02; +/** Entry is for a system file */ +uint8_t const DIR_ATT_SYSTEM = 0X04; +/** Directory entry contains the volume label */ +uint8_t const DIR_ATT_VOLUME_ID = 0X08; +/** Entry is for a directory */ +uint8_t const DIR_ATT_DIRECTORY = 0X10; +/** Old DOS archive bit for backup support */ +uint8_t const DIR_ATT_ARCHIVE = 0X20; +/** Test value for long name entry. Test is + (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */ +uint8_t const DIR_ATT_LONG_NAME = 0X0F; +/** Test mask for long name entry */ +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 */ +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 */ +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 */ +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 */ +static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { + return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; +} +#endif // FatStructs_h diff --git a/Sprinter/Makefile b/Sprinter/Makefile new file mode 100644 index 0000000..618b384 --- /dev/null +++ b/Sprinter/Makefile @@ -0,0 +1,247 @@ +# Sprinter Arduino Project Makefile +# +# Makefile Based on: +# Arduino 0011 Makefile +# Arduino adaptation by mellis, eighthave, oli.keller +# +# This has been tested with Arduino 0022. +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# Detailed instructions for using the makefile: +# +# 1. Modify the line containg "INSTALL_DIR" to point to the directory that +# contains the Arduino installation (for example, under Mac OS X, this +# might be /Applications/arduino-0012). +# +# 2. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.usb*). +# +# 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. +# +# 4. Type "make" and press enter to compile/verify your program. +# +# 5. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id$ + +TARGET = $(notdir $(CURDIR)) +INSTALL_DIR = /home/chris/arduino-0022 +UPLOAD_RATE = 38400 +AVRDUDE_PROGRAMMER = stk500v1 +PORT = /dev/ttyUSB0 +MCU = atmega2560 +#For "old" Arduino Mega +#MCU = atmega1280 +#For Sanguinololu +#MCU = atmega644p +F_CPU = 16000000 + + +############################################################################ +# Below here nothing should be changed... + +ARDUINO = $(INSTALL_DIR)/hardware/arduino/cores/arduino +AVR_TOOLS_PATH = /usr/bin +SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \ +$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \ +$(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \ +$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c +CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \ +$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp +FORMAT = ihex + + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Place -I options here +CINCS = -I$(ARDUINO) +CXXINCS = -I$(ARDUINO) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = -lm + + +# Programming support using avrdude. Settings and variables. +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) + +# 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 +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: applet_files build sizeafter + +build: elf hex + +applet_files: $(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.cxx >> applet/$(TARGET).cpp + +elf: applet/$(TARGET).elf +hex: applet/$(TARGET).hex +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + + # Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex +ELFSIZE = $(SIZE) applet/$(TARGET).elf +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 + + +# 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 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof + + +extcoff: $(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + # Link: create ELF output file from library. +applet/$(TARGET).elf: $(TARGET).pde applet/core.a + $(CC) $(ALL_CFLAGS) -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 $@ + + + +# 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) + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter diff --git a/Sprinter/Sd2Card.cpp b/Sprinter/Sd2Card.cpp new file mode 100644 index 0000000..8222cfd --- /dev/null +++ b/Sprinter/Sd2Card.cpp @@ -0,0 +1,643 @@ +/* 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 + * . + */ +#include +#include "Sd2Card.h" +//------------------------------------------------------------------------------ +#ifndef SOFTWARE_SPI +// functions for hardware SPI +/** Send a byte to the card */ +static void spiSend(uint8_t b) { + SPDR = b; + while (!(SPSR & (1 << SPIF))); +} +/** Receive a byte from the card */ +static uint8_t spiRec(void) { + spiSend(0XFF); + return SPDR; +} +#else // SOFTWARE_SPI +//------------------------------------------------------------------------------ +/** nop to tune soft SPI timing */ +#define nop asm volatile ("nop\n\t") +//------------------------------------------------------------------------------ +/** Soft SPI receive */ +uint8_t spiRec(void) { + uint8_t data = 0; + // no interrupts during byte receive - about 8 us + cli(); + // output pin high - like sending 0XFF + fastDigitalWrite(SPI_MOSI_PIN, HIGH); + + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, HIGH); + + // adjust so SCK is nice + nop; + nop; + + data <<= 1; + + if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; + + fastDigitalWrite(SPI_SCK_PIN, LOW); + } + // enable interrupts + sei(); + return data; +} +//------------------------------------------------------------------------------ +/** Soft SPI send */ +void spiSend(uint8_t data) { + // no interrupts during byte send - about 8 us + cli(); + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, LOW); + + fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); + + data <<= 1; + + fastDigitalWrite(SPI_SCK_PIN, HIGH); + } + // hold SCK high for a few ns + nop; + nop; + nop; + nop; + + fastDigitalWrite(SPI_SCK_PIN, LOW); + // enable interrupts + sei(); +} +#endif // SOFTWARE_SPI +//------------------------------------------------------------------------------ +// send command and return error code. Return zero for OK +uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { + // end read if in partialBlockRead mode + readEnd(); + + // select card + chipSelectLow(); + + // wait up to 300 ms if busy + waitNotBusy(300); + + // send command + spiSend(cmd | 0x40); + + // send argument + for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); + + // send CRC + uint8_t crc = 0XFF; + if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 + if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA + spiSend(crc); + + // wait for response + for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); + return status_; +} +//------------------------------------------------------------------------------ +/** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data blocks in the card + * or zero if an error occurs. + */ +uint32_t Sd2Card::cardSize(void) { + csd_t csd; + if (!readCSD(&csd)) return 0; + if (csd.v1.csd_ver == 0) { + uint8_t read_bl_len = csd.v1.read_bl_len; + uint16_t c_size = (csd.v1.c_size_high << 10) + | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; + uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) + | csd.v1.c_size_mult_low; + return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); + } else if (csd.v2.csd_ver == 1) { + uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) + | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; + return (c_size + 1) << 10; + } else { + error(SD_CARD_ERROR_BAD_CSD); + return 0; + } +} +//------------------------------------------------------------------------------ +void Sd2Card::chipSelectHigh(void) { + digitalWrite(chipSelectPin_, HIGH); +} +//------------------------------------------------------------------------------ +void Sd2Card::chipSelectLow(void) { + digitalWrite(chipSelectPin_, LOW); +} +//------------------------------------------------------------------------------ +/** Erase a range of blocks. + * + * \param[in] firstBlock The address of the first block in the range. + * \param[in] lastBlock The address of the last block in the range. + * + * \note This function requests the SD card to do a flash erase for a + * range of blocks. The data on the card after an erase operation is + * either 0 or 1, depends on the card vendor. The card must support + * single block erase. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { + if (!eraseSingleBlockEnable()) { + error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); + goto fail; + } + if (type_ != SD_CARD_TYPE_SDHC) { + firstBlock <<= 9; + lastBlock <<= 9; + } + if (cardCommand(CMD32, firstBlock) + || cardCommand(CMD33, lastBlock) + || cardCommand(CMD38, 0)) { + error(SD_CARD_ERROR_ERASE); + goto fail; + } + if (!waitNotBusy(SD_ERASE_TIMEOUT)) { + error(SD_CARD_ERROR_ERASE_TIMEOUT); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Determine if card supports single block erase. + * + * \return The value one, true, is returned if single block erase is supported. + * The value zero, false, is returned if single block erase is not supported. + */ +uint8_t Sd2Card::eraseSingleBlockEnable(void) { + csd_t csd; + return readCSD(&csd) ? csd.v1.erase_blk_en : 0; +} +//------------------------------------------------------------------------------ +/** + * Initialize an SD flash memory card. + * + * \param[in] sckRateID SPI clock rate selector. See setSckRate(). + * \param[in] chipSelectPin SD chip select pin number. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. The reason for failure + * can be determined by calling errorCode() and errorData(). + */ +uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { + errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; + chipSelectPin_ = chipSelectPin; + // 16-bit init start time allows over a minute + uint16_t t0 = (uint16_t)millis(); + uint32_t arg; + + // set pin modes + pinMode(chipSelectPin_, OUTPUT); + chipSelectHigh(); + pinMode(SPI_MISO_PIN, INPUT); + pinMode(SPI_MOSI_PIN, OUTPUT); + pinMode(SPI_SCK_PIN, OUTPUT); + +#ifndef SOFTWARE_SPI + // SS must be in output mode even it is not chip select + pinMode(SS_PIN, OUTPUT); + // Enable SPI, Master, clock rate f_osc/128 + SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); + // clear double speed + SPSR &= ~(1 << SPI2X); +#endif // SOFTWARE_SPI + + // must supply min of 74 clock cycles with CS high. + for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); + + chipSelectLow(); + + // command to go idle in SPI mode + while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_CMD0); + goto fail; + } + } + // check SD version + if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { + type(SD_CARD_TYPE_SD1); + } else { + // only need last byte of r7 response + for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); + if (status_ != 0XAA) { + error(SD_CARD_ERROR_CMD8); + goto fail; + } + type(SD_CARD_TYPE_SD2); + } + // initialize card and send host supports SDHC if SD2 + arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; + + while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { + // check for timeout + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_ACMD41); + goto fail; + } + } + // if SD2 read OCR register to check for SDHC card + if (type() == SD_CARD_TYPE_SD2) { + if (cardCommand(CMD58, 0)) { + error(SD_CARD_ERROR_CMD58); + goto fail; + } + if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); + // discard rest of ocr - contains allowed voltage range + for (uint8_t i = 0; i < 3; i++) spiRec(); + } + chipSelectHigh(); + +#ifndef SOFTWARE_SPI + return setSckRate(sckRateID); +#else // SOFTWARE_SPI + return true; +#endif // SOFTWARE_SPI + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** + * Enable or disable partial block reads. + * + * Enabling partial block reads improves performance by allowing a block + * to be read over the SPI bus as several sub-blocks. Errors may occur + * if the time between reads is too long since the SD card may timeout. + * The SPI SS line will be held low until the entire block is read or + * readEnd() is called. + * + * Use this for applications like the Adafruit Wave Shield. + * + * \param[in] value The value TRUE (non-zero) or FALSE (zero).) + */ +void Sd2Card::partialBlockRead(uint8_t value) { + readEnd(); + partialBlockRead_ = value; +} +//------------------------------------------------------------------------------ +/** + * Read a 512 byte block from an SD card device. + * + * \param[in] block Logical block to be read. + * \param[out] dst Pointer to the location that will receive the data. + + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) { + return readData(block, 0, 512, dst); +} +//------------------------------------------------------------------------------ +/** + * Read part of a 512 byte block from an SD card. + * + * \param[in] block Logical block to be read. + * \param[in] offset Number of bytes to skip at start of block + * \param[out] dst Pointer to the location that will receive the data. + * \param[in] count Number of bytes to read + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::readData(uint32_t block, + uint16_t offset, uint16_t count, uint8_t* dst) { + uint16_t n; + if (count == 0) return true; + if ((count + offset) > 512) { + goto fail; + } + if (!inBlock_ || block != block_ || offset < offset_) { + block_ = block; + // use address if not SDHC card + if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; + if (cardCommand(CMD17, block)) { + error(SD_CARD_ERROR_CMD17); + goto fail; + } + if (!waitStartBlock()) { + goto fail; + } + offset_ = 0; + inBlock_ = 1; + } + +#ifdef OPTIMIZE_HARDWARE_SPI + // start first spi transfer + SPDR = 0XFF; + + // skip data before offset + for (;offset_ < offset; offset_++) { + while (!(SPSR & (1 << SPIF))); + SPDR = 0XFF; + } + // transfer data + n = count - 1; + for (uint16_t i = 0; i < n; i++) { + while (!(SPSR & (1 << SPIF))); + dst[i] = SPDR; + SPDR = 0XFF; + } + // wait for last byte + while (!(SPSR & (1 << SPIF))); + dst[n] = SPDR; + +#else // OPTIMIZE_HARDWARE_SPI + + // skip data before offset + for (;offset_ < offset; offset_++) { + spiRec(); + } + // transfer data + for (uint16_t i = 0; i < count; i++) { + dst[i] = spiRec(); + } +#endif // OPTIMIZE_HARDWARE_SPI + + offset_ += count; + if (!partialBlockRead_ || offset_ >= 512) { + // read rest of data, checksum and set chip select high + readEnd(); + } + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Skip remaining data in a block when in partial block read mode. */ +void Sd2Card::readEnd(void) { + if (inBlock_) { + // skip data and crc +#ifdef OPTIMIZE_HARDWARE_SPI + // optimize skip for hardware + SPDR = 0XFF; + while (offset_++ < 513) { + while (!(SPSR & (1 << SPIF))); + SPDR = 0XFF; + } + // wait for last crc byte + while (!(SPSR & (1 << SPIF))); +#else // OPTIMIZE_HARDWARE_SPI + while (offset_++ < 514) spiRec(); +#endif // OPTIMIZE_HARDWARE_SPI + chipSelectHigh(); + inBlock_ = 0; + } +} +//------------------------------------------------------------------------------ +/** read CID or CSR register */ +uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { + uint8_t* dst = reinterpret_cast(buf); + if (cardCommand(cmd, 0)) { + error(SD_CARD_ERROR_READ_REG); + goto fail; + } + if (!waitStartBlock()) goto fail; + // transfer data + for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); + spiRec(); // get first crc byte + spiRec(); // get second crc byte + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** + * Set the SPI clock rate. + * + * \param[in] sckRateID A value in the range [0, 6]. + * + * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum + * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 + * for \a scsRateID = 6. + * + * \return The value one, true, is returned for success and the value zero, + * false, is returned for an invalid value of \a sckRateID. + */ +uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { + if (sckRateID > 6) { + error(SD_CARD_ERROR_SCK_RATE); + return false; + } + // see avr processor datasheet for SPI register bit definitions + if ((sckRateID & 1) || sckRateID == 6) { + SPSR &= ~(1 << SPI2X); + } else { + SPSR |= (1 << SPI2X); + } + SPCR &= ~((1 < SD_READ_TIMEOUT) { + error(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + if (status_ != DATA_START_BLOCK) { + error(SD_CARD_ERROR_READ); + goto fail; + } + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** + * Writes a 512 byte block to an SD card. + * + * \param[in] blockNumber Logical block to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { +#if SD_PROTECT_BLOCK_ZERO + // don't allow write to first block + if (blockNumber == 0) { + error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); + goto fail; + } +#endif // SD_PROTECT_BLOCK_ZERO + + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD24, blockNumber)) { + error(SD_CARD_ERROR_CMD24); + goto fail; + } + if (!writeData(DATA_START_BLOCK, src)) goto fail; + + // wait for flash programming to complete + if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + error(SD_CARD_ERROR_WRITE_TIMEOUT); + goto fail; + } + // response is r2 so get and check two bytes for nonzero + if (cardCommand(CMD13, 0) || spiRec()) { + error(SD_CARD_ERROR_WRITE_PROGRAMMING); + goto fail; + } + chipSelectHigh(); + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** Write one data block in a multiple block write sequence */ +uint8_t Sd2Card::writeData(const uint8_t* src) { + // wait for previous write to finish + if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + error(SD_CARD_ERROR_WRITE_MULTIPLE); + chipSelectHigh(); + return false; + } + return writeData(WRITE_MULTIPLE_TOKEN, src); +} +//------------------------------------------------------------------------------ +// send one block of data for write block or write multiple blocks +uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { +#ifdef OPTIMIZE_HARDWARE_SPI + + // send data - optimized loop + SPDR = token; + + // send two byte per iteration + for (uint16_t i = 0; i < 512; i += 2) { + while (!(SPSR & (1 << SPIF))); + SPDR = src[i]; + while (!(SPSR & (1 << SPIF))); + SPDR = src[i+1]; + } + + // wait for last data byte + while (!(SPSR & (1 << SPIF))); + +#else // OPTIMIZE_HARDWARE_SPI + spiSend(token); + for (uint16_t i = 0; i < 512; i++) { + spiSend(src[i]); + } +#endif // OPTIMIZE_HARDWARE_SPI + spiSend(0xff); // dummy crc + spiSend(0xff); // dummy crc + + status_ = spiRec(); + if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { + error(SD_CARD_ERROR_WRITE); + chipSelectHigh(); + return false; + } + return true; +} +//------------------------------------------------------------------------------ +/** Start a write multiple blocks sequence. + * + * \param[in] blockNumber Address of first block in sequence. + * \param[in] eraseCount The number of blocks to be pre-erased. + * + * \note This function is used with writeData() and writeStop() + * for optimized multiple block writes. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { +#if SD_PROTECT_BLOCK_ZERO + // don't allow write to first block + if (blockNumber == 0) { + error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); + goto fail; + } +#endif // SD_PROTECT_BLOCK_ZERO + // send pre-erase count + if (cardAcmd(ACMD23, eraseCount)) { + error(SD_CARD_ERROR_ACMD23); + goto fail; + } + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD25, blockNumber)) { + error(SD_CARD_ERROR_CMD25); + goto fail; + } + return true; + + fail: + chipSelectHigh(); + return false; +} +//------------------------------------------------------------------------------ +/** End a write multiple blocks sequence. + * +* \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t Sd2Card::writeStop(void) { + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + spiSend(STOP_TRAN_TOKEN); + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + chipSelectHigh(); + return true; + + fail: + error(SD_CARD_ERROR_STOP_TRAN); + chipSelectHigh(); + return false; +} diff --git a/Sprinter/Sd2Card.h b/Sprinter/Sd2Card.h new file mode 100644 index 0000000..73b46fb --- /dev/null +++ b/Sprinter/Sd2Card.h @@ -0,0 +1,233 @@ +/* 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 + * . + */ +#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 diff --git a/Sprinter/Sd2PinMap.h b/Sprinter/Sd2PinMap.h new file mode 100644 index 0000000..4bd75a3 --- /dev/null +++ b/Sprinter/Sd2PinMap.h @@ -0,0 +1,353 @@ +/* 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 + * . + */ +// Warning this file was generated by a program. +#ifndef Sd2PinMap_h +#define Sd2PinMap_h +#include + +//------------------------------------------------------------------------------ +/** 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 diff --git a/Sprinter/SdFat.h b/Sprinter/SdFat.h new file mode 100644 index 0000000..048fa71 --- /dev/null +++ b/Sprinter/SdFat.h @@ -0,0 +1,547 @@ +/* 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 + * . + */ +#ifndef SdFat_h +#define SdFat_h +/** + * \file + * SdFile and SdVolume classes + */ +#include +#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 diff --git a/Sprinter/SdFatUtil.h b/Sprinter/SdFatUtil.h new file mode 100644 index 0000000..8bf9048 --- /dev/null +++ b/Sprinter/SdFatUtil.h @@ -0,0 +1,70 @@ +/* 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 + * . + */ +#ifndef SdFatUtil_h +#define SdFatUtil_h +/** + * \file + * Useful utility functions. + */ +#include +#include +/** 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(__brkval) == 0) { + // if no heap use from end of bss section + free_memory = reinterpret_cast(&free_memory) + - reinterpret_cast(&__bss_end); + } else { + // use from top of stack to heap + free_memory = reinterpret_cast(&free_memory) + - reinterpret_cast(__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 diff --git a/Sprinter/SdFatmainpage.h b/Sprinter/SdFatmainpage.h new file mode 100644 index 0000000..73b3b63 --- /dev/null +++ b/Sprinter/SdFatmainpage.h @@ -0,0 +1,202 @@ +/* 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 + * . + */ + +/** +\mainpage Arduino SdFat Library +
Copyright © 2009 by William Greiman +
+ +\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 + Adafruit Industries + Wave Shield. + +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 + + + */ diff --git a/Sprinter/SdFile.cpp b/Sprinter/SdFile.cpp new file mode 100644 index 0000000..0a27159 --- /dev/null +++ b/Sprinter/SdFile.cpp @@ -0,0 +1,1252 @@ +/* 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 + * . + */ +#include "SdFat.h" +#include +#include +//------------------------------------------------------------------------------ +// callback function for date/time +void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; + +#if ALLOW_DEPRECATED_FUNCTIONS +// suppress cpplint warnings with NOLINT comment +void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT +#endif // ALLOW_DEPRECATED_FUNCTIONS +//------------------------------------------------------------------------------ +// add a cluster to a file +uint8_t SdFile::addCluster() { + if (!vol_->allocContiguous(1, &curCluster_)) return false; + + // if first cluster of file link to directory entry + if (firstCluster_ == 0) { + firstCluster_ = curCluster_; + flags_ |= F_FILE_DIR_DIRTY; + } + return true; +} +//------------------------------------------------------------------------------ +// Add a cluster to a directory file and zero the cluster. +// return with first block of cluster in the cache +uint8_t SdFile::addDirCluster(void) { + if (!addCluster()) return false; + + // zero data in cluster insure first cluster is in cache + uint32_t block = vol_->clusterStartBlock(curCluster_); + for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { + if (!SdVolume::cacheZeroBlock(block + i - 1)) return false; + } + // Increase directory file size by cluster size + fileSize_ += 512UL << vol_->clusterSizeShift_; + return true; +} +//------------------------------------------------------------------------------ +// cache a file's directory entry +// return pointer to cached entry or null for failure +dir_t* SdFile::cacheDirEntry(uint8_t action) { + if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; + return SdVolume::cacheBuffer_.dir + dirIndex_; +} +//------------------------------------------------------------------------------ +/** + * Close a file and force cached data and directory information + * to be written to the storage device. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include no file is open or an I/O error. + */ +uint8_t SdFile::close(void) { + if (!sync())return false; + type_ = FAT_FILE_TYPE_CLOSED; + return true; +} +//------------------------------------------------------------------------------ +/** + * Check for contiguous file and return its raw block range. + * + * \param[out] bgnBlock the first block address for the file. + * \param[out] endBlock the last block address for the file. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include file is not contiguous, file has zero length + * or an I/O error occurred. + */ +uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { + // error if no blocks + if (firstCluster_ == 0) return false; + + for (uint32_t c = firstCluster_; ; c++) { + uint32_t next; + if (!vol_->fatGet(c, &next)) return false; + + // check for contiguous + if (next != (c + 1)) { + // error if not end of chain + if (!vol_->isEOC(next)) return false; + *bgnBlock = vol_->clusterStartBlock(firstCluster_); + *endBlock = vol_->clusterStartBlock(c) + + vol_->blocksPerCluster_ - 1; + return true; + } + } +} +//------------------------------------------------------------------------------ +/** + * Create and open a new contiguous file of a specified size. + * + * \note This function only supports short DOS 8.3 names. + * See open() for more information. + * + * \param[in] dirFile The directory where the file will be created. + * \param[in] fileName A valid DOS 8.3 file name. + * \param[in] size The desired file size. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include \a fileName contains + * an invalid DOS 8.3 file name, the FAT volume has not been initialized, + * a file is already open, the file already exists, the root + * directory is full or an I/O error. + * + */ +uint8_t SdFile::createContiguous(SdFile* dirFile, + const char* fileName, uint32_t size) { + // don't allow zero length file + if (size == 0) return false; + if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false; + + // calculate number of clusters needed + uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; + + // allocate clusters + if (!vol_->allocContiguous(count, &firstCluster_)) { + remove(); + return false; + } + fileSize_ = size; + + // insure sync() will update dir entry + flags_ |= F_FILE_DIR_DIRTY; + return sync(); +} +//------------------------------------------------------------------------------ +/** + * Return a files directory entry + * + * \param[out] dir Location for return of the files directory entry. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdFile::dirEntry(dir_t* dir) { + // make sure fields on SD are correct + if (!sync()) return false; + + // read entry + dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); + if (!p) return false; + + // copy to caller's struct + memcpy(dir, p, sizeof(dir_t)); + return true; +} +//------------------------------------------------------------------------------ +/** + * Format the name field of \a dir into the 13 byte array + * \a name in standard 8.3 short name format. + * + * \param[in] dir The directory structure containing the name. + * \param[out] name A 13 byte char array for the formatted name. + */ +void SdFile::dirName(const dir_t& dir, char* name) { + uint8_t j = 0; + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) name[j++] = '.'; + name[j++] = dir.name[i]; + } + name[j] = 0; +} +//------------------------------------------------------------------------------ +/** List directory contents to Serial. + * + * \param[in] flags The inclusive OR of + * + * LS_DATE - %Print file modification date + * + * LS_SIZE - %Print file size. + * + * LS_R - Recursive list of subdirectories. + * + * \param[in] indent Amount of space before file name. Used for recursive + * list to indicate subdirectory level. + */ +void SdFile::ls(uint8_t flags, uint8_t indent) { + dir_t* p; + + rewind(); + while ((p = readDirCache())) { + // done if past last used entry + if (p->name[0] == DIR_NAME_FREE) break; + + // skip deleted entry and entries for . and .. + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; + + // only list subdirectories and files + if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; + + // print any indent spaces + for (int8_t i = 0; i < indent; i++) Serial.print(' '); + + // print file name with possible blank fill + printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); + + // print modify date/time if requested + if (flags & LS_DATE) { + printFatDate(p->lastWriteDate); + Serial.print(' '); + printFatTime(p->lastWriteTime); + } + // print size if requested + if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { + Serial.print(' '); + Serial.print(p->fileSize); + } + Serial.println(); + + // list subdirectory content if requested + if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { + uint16_t index = curPosition()/32 - 1; + SdFile s; + if (s.open(this, index, O_READ)) s.ls(flags, indent + 2); + seekSet(32 * (index + 1)); + } + } +} +//------------------------------------------------------------------------------ +// format directory name field from a 8.3 name string +uint8_t SdFile::make83Name(const char* str, uint8_t* name) { + uint8_t c; + uint8_t n = 7; // max index for part before dot + uint8_t i = 0; + // blank fill name and extension + while (i < 11) name[i++] = ' '; + i = 0; + while ((c = *str++) != '\0') { + if (c == '.') { + if (n == 10) return false; // only one dot allowed + n = 10; // max index for full 8.3 name + i = 8; // place for extension + } else { + // illegal FAT characters + PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); + uint8_t b; + while ((b = pgm_read_byte(p++))) if (b == c) return false; + // check size and only allow ASCII printable characters + if (i > n || c < 0X21 || c > 0X7E)return false; + // only upper case allowed in 8.3 names - convert lower to upper + name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); + } + } + // must have a file name, extension is optional + return name[0] != ' '; +} +//------------------------------------------------------------------------------ +/** Make a new directory. + * + * \param[in] dir An open SdFat instance for the directory that will containing + * the new directory. + * + * \param[in] dirName A valid 8.3 DOS name for the new directory. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include this SdFile is already open, \a dir is not a + * directory, \a dirName is invalid or already exists in \a dir. + */ +uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { + dir_t d; + + // create a normal file + if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false; + + // convert SdFile to directory + flags_ = O_READ; + type_ = FAT_FILE_TYPE_SUBDIR; + + // allocate and zero first cluster + if (!addDirCluster())return false; + + // force entry to SD + if (!sync()) return false; + + // cache entry - should already be in cache due to sync() call + dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!p) return false; + + // change directory entry attribute + p->attributes = DIR_ATT_DIRECTORY; + + // make entry for '.' + memcpy(&d, p, sizeof(d)); + for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; + d.name[0] = '.'; + + // cache block for '.' and '..' + uint32_t block = vol_->clusterStartBlock(firstCluster_); + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; + + // copy '.' to block + memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); + + // make entry for '..' + d.name[1] = '.'; + if (dir->isRoot()) { + d.firstClusterLow = 0; + d.firstClusterHigh = 0; + } else { + d.firstClusterLow = dir->firstCluster_ & 0XFFFF; + d.firstClusterHigh = dir->firstCluster_ >> 16; + } + // copy '..' to block + memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); + + // set position after '..' + curPosition_ = 2 * sizeof(d); + + // write first block + return SdVolume::cacheFlush(); +} +//------------------------------------------------------------------------------ +/** + * Open a file or directory by name. + * + * \param[in] dirFile An open SdFat instance for the directory containing the + * file to be opened. + * + * \param[in] fileName A valid 8.3 DOS name for a file to be opened. + * + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of flags from the following list + * + * O_READ - Open for reading. + * + * O_RDONLY - Same as O_READ. + * + * O_WRITE - Open for writing. + * + * O_WRONLY - Same as O_WRITE. + * + * O_RDWR - Open for reading and writing. + * + * O_APPEND - If set, the file offset shall be set to the end of the + * file prior to each write. + * + * O_CREAT - If the file exists, this flag has no effect except as noted + * under O_EXCL below. Otherwise, the file shall be created + * + * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. + * + * O_SYNC - Call sync() after each write. This flag should not be used with + * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. + * These functions do character at a time writes so sync() will be called + * after each byte. + * + * O_TRUNC - If the file exists and is a regular file, and the file is + * successfully opened and is not read only, its length shall be truncated to 0. + * + * \note Directory files must be opened read only. Write and truncation is + * not allowed for directory files. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include this SdFile is already open, \a difFile is not + * a directory, \a fileName is invalid, the file does not exist + * or can't be opened in the access mode specified by oflag. + */ +uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { + uint8_t dname[11]; + dir_t* p; + + // error if already open + if (isOpen())return false; + + if (!make83Name(fileName, dname)) return false; + vol_ = dirFile->vol_; + dirFile->rewind(); + + // bool for empty entry found + uint8_t emptyFound = false; + + // search for file + while (dirFile->curPosition_ < dirFile->fileSize_) { + uint8_t index = 0XF & (dirFile->curPosition_ >> 5); + p = dirFile->readDirCache(); + if (p == NULL) return false; + + if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { + // remember first empty slot + if (!emptyFound) { + emptyFound = true; + dirIndex_ = index; + dirBlock_ = SdVolume::cacheBlockNumber_; + } + // done if no entries follow + if (p->name[0] == DIR_NAME_FREE) break; + } else if (!memcmp(dname, p->name, 11)) { + // don't open existing file if O_CREAT and O_EXCL + if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; + + // open found file + return openCachedEntry(0XF & index, oflag); + } + } + // only create file if O_CREAT and O_WRITE + if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; + + // cache found slot or add cluster if end of file + if (emptyFound) { + p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!p) return false; + } else { + if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false; + + // add and zero cluster for dirFile - first cluster is in cache for write + if (!dirFile->addDirCluster()) return false; + + // use first entry in cluster + dirIndex_ = 0; + p = SdVolume::cacheBuffer_.dir; + } + // initialize as empty file + memset(p, 0, sizeof(dir_t)); + memcpy(p->name, dname, 11); + + // set timestamps + if (dateTime_) { + // call user function + dateTime_(&p->creationDate, &p->creationTime); + } else { + // use default date/time + p->creationDate = FAT_DEFAULT_DATE; + p->creationTime = FAT_DEFAULT_TIME; + } + p->lastAccessDate = p->creationDate; + p->lastWriteDate = p->creationDate; + p->lastWriteTime = p->creationTime; + + // force write of entry to SD + if (!SdVolume::cacheFlush()) return false; + + // open entry in cache + return openCachedEntry(dirIndex_, oflag); +} +//------------------------------------------------------------------------------ +/** + * Open a file by index. + * + * \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. + * + * See open() by fileName for definition of flags and return values. + * + */ +uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { + // error if already open + if (isOpen())return false; + + // don't open existing file if O_CREAT and O_EXCL - user call error + if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; + + vol_ = dirFile->vol_; + + // seek to location of entry + if (!dirFile->seekSet(32 * index)) return false; + + // read entry into cache + dir_t* p = dirFile->readDirCache(); + if (p == NULL) return false; + + // error if empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_FREE || + p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + return false; + } + // open cached entry + return openCachedEntry(index & 0XF, oflag); +} +//------------------------------------------------------------------------------ +// open a cached directory entry. Assumes vol_ is initializes +uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { + // location of entry in cache + dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; + + // write or truncate is an error for a directory or read-only file + if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { + if (oflag & (O_WRITE | O_TRUNC)) return false; + } + // remember location of directory entry on SD + dirIndex_ = dirIndex; + dirBlock_ = SdVolume::cacheBlockNumber_; + + // copy first cluster number for directory fields + firstCluster_ = (uint32_t)p->firstClusterHigh << 16; + firstCluster_ |= p->firstClusterLow; + + // make sure it is a normal file or subdirectory + if (DIR_IS_FILE(p)) { + fileSize_ = p->fileSize; + type_ = FAT_FILE_TYPE_NORMAL; + } else if (DIR_IS_SUBDIR(p)) { + if (!vol_->chainSize(firstCluster_, &fileSize_)) return false; + type_ = FAT_FILE_TYPE_SUBDIR; + } else { + return false; + } + // save open flags for read/write + flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); + + // set to start of file + curCluster_ = 0; + curPosition_ = 0; + + // truncate file to zero length if requested + if (oflag & O_TRUNC) return truncate(0); + return true; +} +//------------------------------------------------------------------------------ +/** + * Open a volume's root directory. + * + * \param[in] vol The FAT volume containing the root directory to be opened. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the FAT volume has not been initialized + * or it a FAT12 volume. + */ +uint8_t SdFile::openRoot(SdVolume* vol) { + // error if file is already open + if (isOpen()) return false; + + if (vol->fatType() == 16) { + type_ = FAT_FILE_TYPE_ROOT16; + firstCluster_ = 0; + fileSize_ = 32 * vol->rootDirEntryCount(); + } else if (vol->fatType() == 32) { + type_ = FAT_FILE_TYPE_ROOT32; + firstCluster_ = vol->rootDirStart(); + if (!vol->chainSize(firstCluster_, &fileSize_)) return false; + } else { + // volume is not initialized or FAT12 + return false; + } + vol_ = vol; + // read only + flags_ = O_READ; + + // set to start of file + curCluster_ = 0; + curPosition_ = 0; + + // root has no directory entry + dirBlock_ = 0; + dirIndex_ = 0; + return true; +} +//------------------------------------------------------------------------------ +/** %Print the name field of a directory entry in 8.3 format to Serial. + * + * \param[in] dir The directory structure containing the name. + * \param[in] width Blank fill name if length is less than \a width. + */ +void SdFile::printDirName(const dir_t& dir, uint8_t width) { + uint8_t w = 0; + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) { + Serial.print('.'); + w++; + } + Serial.print(dir.name[i]); + w++; + } + if (DIR_IS_SUBDIR(&dir)) { + Serial.print('/'); + w++; + } + while (w < width) { + Serial.print(' '); + w++; + } +} +//------------------------------------------------------------------------------ +/** %Print a directory date field to Serial. + * + * Format is yyyy-mm-dd. + * + * \param[in] fatDate The date field from a directory entry. + */ +void SdFile::printFatDate(uint16_t fatDate) { + Serial.print(FAT_YEAR(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_MONTH(fatDate)); + Serial.print('-'); + printTwoDigits(FAT_DAY(fatDate)); +} +//------------------------------------------------------------------------------ +/** %Print a directory time field to Serial. + * + * Format is hh:mm:ss. + * + * \param[in] fatTime The time field from a directory entry. + */ +void SdFile::printFatTime(uint16_t fatTime) { + printTwoDigits(FAT_HOUR(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_MINUTE(fatTime)); + Serial.print(':'); + printTwoDigits(FAT_SECOND(fatTime)); +} +//------------------------------------------------------------------------------ +/** %Print a value as two digits to Serial. + * + * \param[in] v Value to be printed, 0 <= \a v <= 99 + */ +void SdFile::printTwoDigits(uint8_t v) { + char str[3]; + str[0] = '0' + v/10; + str[1] = '0' + v % 10; + str[2] = 0; + Serial.print(str); +} +//------------------------------------------------------------------------------ +/** + * Read data from a file starting at the current position. + * + * \param[out] buf Pointer to the location that will receive the data. + * + * \param[in] nbyte Maximum number of bytes to read. + * + * \return For success read() returns the number of bytes read. + * A value less than \a nbyte, including zero, will be returned + * if end of file is reached. + * If an error occurs, read() returns -1. Possible errors include + * read() called before a file has been opened, corrupt file system + * or an I/O error occurred. + */ +int16_t SdFile::read(void* buf, uint16_t nbyte) { + uint8_t* dst = reinterpret_cast(buf); + + // error if not open or write only + if (!isOpen() || !(flags_ & O_READ)) return -1; + + // max bytes left in file + if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; + + // amount left to read + uint16_t toRead = nbyte; + while (toRead > 0) { + uint32_t block; // raw device block number + uint16_t offset = curPosition_ & 0X1FF; // offset in block + if (type_ == FAT_FILE_TYPE_ROOT16) { + block = vol_->rootDirStart() + (curPosition_ >> 9); + } else { + uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); + if (offset == 0 && blockOfCluster == 0) { + // start of new cluster + if (curPosition_ == 0) { + // use first cluster in file + curCluster_ = firstCluster_; + } else { + // get next cluster from FAT + if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; + } + } + block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; + } + uint16_t n = toRead; + + // amount to be read from current block + if (n > (512 - offset)) n = 512 - offset; + + // no buffering needed if n == 512 or user requests no buffering + if ((unbufferedRead() || n == 512) && + block != SdVolume::cacheBlockNumber_) { + if (!vol_->readData(block, offset, n, dst)) return -1; + dst += n; + } else { + // read block to cache and copy data to caller + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1; + uint8_t* src = SdVolume::cacheBuffer_.data + offset; + uint8_t* end = src + n; + while (src != end) *dst++ = *src++; + } + curPosition_ += n; + toRead -= n; + } + return nbyte; +} +//------------------------------------------------------------------------------ +/** + * Read the next directory entry from a directory file. + * + * \param[out] dir The dir_t struct that will receive the data. + * + * \return For success readDir() returns the number of bytes read. + * A value of zero will be returned if end of file is reached. + * If an error occurs, readDir() returns -1. Possible errors include + * readDir() called before a directory has been opened, this is not + * a directory file or an I/O error occurred. + */ +int8_t SdFile::readDir(dir_t* dir) { + int8_t n; + // if not a directory file or miss-positioned return an error + if (!isDir() || (0X1F & curPosition_)) return -1; + + while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { + // last entry if DIR_NAME_FREE + if (dir->name[0] == DIR_NAME_FREE) break; + // skip empty entries and entry for . and .. + if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; + // return if normal file or subdirectory + if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; + } + // error, end of file, or past last entry + return n < 0 ? -1 : 0; +} +//------------------------------------------------------------------------------ +// Read next directory entry into the cache +// Assumes file is correctly positioned +dir_t* SdFile::readDirCache(void) { + // error if not directory + if (!isDir()) return NULL; + + // index of entry in cache + uint8_t i = (curPosition_ >> 5) & 0XF; + + // use read to locate and cache block + if (read() < 0) return NULL; + + // advance to next entry + curPosition_ += 31; + + // return pointer to entry + return (SdVolume::cacheBuffer_.dir + i); +} +//------------------------------------------------------------------------------ +/** + * Remove a file. + * + * The directory entry and all data for the file are deleted. + * + * \note This function should not be used to delete the 8.3 version of a + * file that has a long name. For example if a file has the long name + * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the file read-only, is a directory, + * or an I/O error occurred. + */ +uint8_t SdFile::remove(void) { + // free any clusters - will fail if read-only or directory + if (!truncate(0)) return false; + + // cache directory entry + dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) return false; + + // mark entry deleted + d->name[0] = DIR_NAME_DELETED; + + // set this SdFile closed + type_ = FAT_FILE_TYPE_CLOSED; + + // write entry to SD + return SdVolume::cacheFlush(); +} +//------------------------------------------------------------------------------ +/** + * Remove a file. + * + * The directory entry and all data for the file are deleted. + * + * \param[in] dirFile The directory that contains the file. + * \param[in] fileName The name of the file to be removed. + * + * \note This function should not be used to delete the 8.3 version of a + * file that has a long name. For example if a file has the long name + * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the file is a directory, is read only, + * \a dirFile is not a directory, \a fileName is not found + * or an I/O error occurred. + */ +uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { + SdFile file; + if (!file.open(dirFile, fileName, O_WRITE)) return false; + return file.remove(); +} +//------------------------------------------------------------------------------ +/** Remove a directory file. + * + * The directory file will be removed only if it is empty and is not the + * root directory. rmDir() follows DOS and Windows and ignores the + * read-only attribute for the directory. + * + * \note This function should not be used to delete the 8.3 version of a + * directory that has a long name. For example if a directory has the + * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include the file is not a directory, is the root + * directory, is not empty, or an I/O error occurred. + */ +uint8_t SdFile::rmDir(void) { + // must be open subdirectory + if (!isSubDir()) return false; + + rewind(); + + // make sure directory is empty + while (curPosition_ < fileSize_) { + dir_t* p = readDirCache(); + if (p == NULL) return false; + // done if past last used entry + if (p->name[0] == DIR_NAME_FREE) break; + // skip empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; + // error not empty + if (DIR_IS_FILE_OR_SUBDIR(p)) return false; + } + // convert empty directory to normal file for remove + type_ = FAT_FILE_TYPE_NORMAL; + flags_ |= O_WRITE; + return remove(); +} +//------------------------------------------------------------------------------ +/** Recursively delete a directory and all contained files. + * + * This is like the Unix/Linux 'rm -rf *' if called with the root directory + * hence the name. + * + * Warning - This will remove all contents of the directory including + * subdirectories. The directory will then be removed if it is not root. + * The read-only attribute for files will be ignored. + * + * \note This function should not be used to delete the 8.3 version of + * a directory that has a long name. See remove() and rmDir(). + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdFile::rmRfStar(void) { + rewind(); + while (curPosition_ < fileSize_) { + SdFile f; + + // remember position + uint16_t index = curPosition_/32; + + dir_t* p = readDirCache(); + if (!p) return false; + + // done if past last entry + if (p->name[0] == DIR_NAME_FREE) break; + + // skip empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; + + // skip if part of long file name or volume label in root + if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; + + if (!f.open(this, index, O_READ)) return false; + if (f.isSubDir()) { + // recursively delete + if (!f.rmRfStar()) return false; + } else { + // ignore read-only + f.flags_ |= O_WRITE; + if (!f.remove()) return false; + } + // position to next entry if required + if (curPosition_ != (32*(index + 1))) { + if (!seekSet(32*(index + 1))) return false; + } + } + // don't try to delete root + if (isRoot()) return true; + return rmDir(); +} +//------------------------------------------------------------------------------ +/** + * Sets a file's position. + * + * \param[in] pos The new position in bytes from the beginning of the file. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdFile::seekSet(uint32_t pos) { + // error if file not open or seek past end of file + if (!isOpen() || pos > fileSize_) return false; + + if (type_ == FAT_FILE_TYPE_ROOT16) { + curPosition_ = pos; + return true; + } + if (pos == 0) { + // set position to start of file + curCluster_ = 0; + curPosition_ = 0; + return true; + } + // calculate cluster index for cur and new position + uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); + uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); + + if (nNew < nCur || curPosition_ == 0) { + // must follow chain from first cluster + curCluster_ = firstCluster_; + } else { + // advance from curPosition + nNew -= nCur; + } + while (nNew--) { + if (!vol_->fatGet(curCluster_, &curCluster_)) return false; + } + curPosition_ = pos; + return true; +} +//------------------------------------------------------------------------------ +/** + * The sync() call causes all modified data and directory fields + * to be written to the storage device. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include a call to sync() before a file has been + * opened or an I/O error. + */ +uint8_t SdFile::sync(void) { + // only allow open files and directories + if (!isOpen()) return false; + + if (flags_ & F_FILE_DIR_DIRTY) { + dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) return false; + + // do not set filesize for dir files + if (!isDir()) d->fileSize = fileSize_; + + // update first cluster fields + d->firstClusterLow = firstCluster_ & 0XFFFF; + d->firstClusterHigh = firstCluster_ >> 16; + + // set modify time if user supplied a callback date/time function + if (dateTime_) { + dateTime_(&d->lastWriteDate, &d->lastWriteTime); + d->lastAccessDate = d->lastWriteDate; + } + // clear directory dirty + flags_ &= ~F_FILE_DIR_DIRTY; + } + return SdVolume::cacheFlush(); +} +//------------------------------------------------------------------------------ +/** + * Set a file's timestamps in its directory entry. + * + * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive + * OR of flags from the following list + * + * T_ACCESS - Set the file's last access date. + * + * T_CREATE - Set the file's creation date and time. + * + * T_WRITE - Set the file's last write/modification date and time. + * + * \param[in] year Valid range 1980 - 2107 inclusive. + * + * \param[in] month Valid range 1 - 12 inclusive. + * + * \param[in] day Valid range 1 - 31 inclusive. + * + * \param[in] hour Valid range 0 - 23 inclusive. + * + * \param[in] minute Valid range 0 - 59 inclusive. + * + * \param[in] second Valid range 0 - 59 inclusive + * + * \note It is possible to set an invalid date since there is no check for + * the number of days in a month. + * + * \note + * Modify and access timestamps may be overwritten if a date time callback + * function has been set by dateTimeCallback(). + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, + uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { + if (!isOpen() + || year < 1980 + || year > 2107 + || month < 1 + || month > 12 + || day < 1 + || day > 31 + || hour > 23 + || minute > 59 + || second > 59) { + return false; + } + dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) return false; + + uint16_t dirDate = FAT_DATE(year, month, day); + uint16_t dirTime = FAT_TIME(hour, minute, second); + if (flags & T_ACCESS) { + d->lastAccessDate = dirDate; + } + if (flags & T_CREATE) { + d->creationDate = dirDate; + d->creationTime = dirTime; + // seems to be units of 1/100 second not 1/10 as Microsoft states + d->creationTimeTenths = second & 1 ? 100 : 0; + } + if (flags & T_WRITE) { + d->lastWriteDate = dirDate; + d->lastWriteTime = dirTime; + } + SdVolume::cacheSetDirty(); + return sync(); +} +//------------------------------------------------------------------------------ +/** + * Truncate a file to a specified length. The current file position + * will be maintained if it is less than or equal to \a length otherwise + * it will be set to end of file. + * + * \param[in] length The desired length for the file. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + * Reasons for failure include file is read only, file is a directory, + * \a length is greater than the current file size or an I/O error occurs. + */ +uint8_t SdFile::truncate(uint32_t length) { +// error if not a normal file or read-only + if (!isFile() || !(flags_ & O_WRITE)) return false; + + // error if length is greater than current size + if (length > fileSize_) return false; + + // fileSize and length are zero - nothing to do + if (fileSize_ == 0) return true; + + // remember position for seek after truncation + uint32_t newPos = curPosition_ > length ? length : curPosition_; + + // position to last cluster in truncated file + if (!seekSet(length)) return false; + + if (length == 0) { + // free all clusters + if (!vol_->freeChain(firstCluster_)) return false; + firstCluster_ = 0; + } else { + uint32_t toFree; + if (!vol_->fatGet(curCluster_, &toFree)) return false; + + if (!vol_->isEOC(toFree)) { + // free extra clusters + if (!vol_->freeChain(toFree)) return false; + + // current cluster is end of chain + if (!vol_->fatPutEOC(curCluster_)) return false; + } + } + fileSize_ = length; + + // need to update directory entry + flags_ |= F_FILE_DIR_DIRTY; + + if (!sync()) return false; + + // set file to correct position + return seekSet(newPos); +} +//------------------------------------------------------------------------------ +/** + * Write data to an open file. + * + * \note Data is moved to the cache but may not be written to the + * storage device until sync() is called. + * + * \param[in] buf Pointer to the location of the data to be written. + * + * \param[in] nbyte Number of bytes to write. + * + * \return For success write() returns the number of bytes written, always + * \a nbyte. If an error occurs, write() returns -1. Possible errors + * include write() is called before a file has been opened, write is called + * for a read-only file, device is full, a corrupt file system or an I/O error. + * + */ +int16_t SdFile::write(const void* buf, uint16_t nbyte) { + // convert void* to uint8_t* - must be before goto statements + const uint8_t* src = reinterpret_cast(buf); + + // number of bytes left to write - must be before goto statements + uint16_t nToWrite = nbyte; + + // error if not a normal file or is read-only + if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; + + // seek to end of file if append flag + if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { + if (!seekEnd()) goto writeErrorReturn; + } + + while (nToWrite > 0) { + uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); + uint16_t blockOffset = curPosition_ & 0X1FF; + if (blockOfCluster == 0 && blockOffset == 0) { + // start of new cluster + if (curCluster_ == 0) { + if (firstCluster_ == 0) { + // allocate first cluster of file + if (!addCluster()) goto writeErrorReturn; + } else { + curCluster_ = firstCluster_; + } + } else { + uint32_t next; + if (!vol_->fatGet(curCluster_, &next)) return false; + if (vol_->isEOC(next)) { + // add cluster if at end of chain + if (!addCluster()) goto writeErrorReturn; + } else { + curCluster_ = next; + } + } + } + // max space in block + uint16_t n = 512 - blockOffset; + + // lesser of space and amount to write + if (n > nToWrite) n = nToWrite; + + // block for data write + uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; + if (n == 512) { + // full block - don't need to use cache + // invalidate cache if block is in cache + if (SdVolume::cacheBlockNumber_ == block) { + SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; + } + if (!vol_->writeBlock(block, src)) goto writeErrorReturn; + src += 512; + } else { + if (blockOffset == 0 && curPosition_ >= fileSize_) { + // start of new block don't need to read into cache + if (!SdVolume::cacheFlush()) goto writeErrorReturn; + SdVolume::cacheBlockNumber_ = block; + SdVolume::cacheSetDirty(); + } else { + // rewrite part of block + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { + goto writeErrorReturn; + } + } + uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; + uint8_t* end = dst + n; + while (dst != end) *dst++ = *src++; + } + nToWrite -= n; + curPosition_ += n; + } + if (curPosition_ > fileSize_) { + // update fileSize and insure sync will update dir entry + fileSize_ = curPosition_; + flags_ |= F_FILE_DIR_DIRTY; + } else if (dateTime_ && nbyte) { + // insure sync will update modified date and time + flags_ |= F_FILE_DIR_DIRTY; + } + + if (flags_ & O_SYNC) { + if (!sync()) goto writeErrorReturn; + } + return nbyte; + + writeErrorReturn: + // return for write error + writeError = true; + return -1; +} +//------------------------------------------------------------------------------ +/** + * Write a byte to a file. Required by the Arduino Print class. + * + * Use SdFile::writeError to check for errors. + */ +void SdFile::write(uint8_t b) { + write(&b, 1); +} +//------------------------------------------------------------------------------ +/** + * Write a string to a file. Used by the Arduino Print class. + * + * Use SdFile::writeError to check for errors. + */ +void SdFile::write(const char* str) { + write(str, strlen(str)); +} +//------------------------------------------------------------------------------ +/** + * Write a PROGMEM string to a file. + * + * Use SdFile::writeError to check for errors. + */ +void SdFile::write_P(PGM_P str) { + for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); +} +//------------------------------------------------------------------------------ +/** + * Write a PROGMEM string followed by CR/LF to a file. + * + * Use SdFile::writeError to check for errors. + */ +void SdFile::writeln_P(PGM_P str) { + write_P(str); + println(); +} diff --git a/Sprinter/SdInfo.h b/Sprinter/SdInfo.h new file mode 100644 index 0000000..acde74d --- /dev/null +++ b/Sprinter/SdInfo.h @@ -0,0 +1,232 @@ +/* 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 + * . + */ +#ifndef SdInfo_h +#define SdInfo_h +#include +// 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 diff --git a/Sprinter/SdVolume.cpp b/Sprinter/SdVolume.cpp new file mode 100644 index 0000000..3c1e641 --- /dev/null +++ b/Sprinter/SdVolume.cpp @@ -0,0 +1,295 @@ +/* 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 + * . + */ +#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; +} diff --git a/Sprinter/Sprinter.h b/Sprinter/Sprinter.h new file mode 100644 index 0000000..4e3c7ea --- /dev/null +++ b/Sprinter/Sprinter.h @@ -0,0 +1,36 @@ +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// Licence: GPL +#include + +void get_command(); +void process_commands(); + +void manage_inactivity(byte debug); + +void manage_heater(); +float temp2analog(int celsius); +float temp2analogBed(int celsius); +float analog2temp(int raw); +float analog2tempBed(int raw); + +void FlushSerialRequestResend(); +void ClearToSend(); + +void get_coordinates(); +void prepare_move(); +void linear_move(unsigned long x_steps_remaining, unsigned long y_steps_remaining, unsigned long z_steps_remaining, unsigned long e_steps_remaining); +void disable_x(); +void disable_y(); +void disable_z(); +void disable_e(); +void enable_x(); +void enable_y(); +void enable_z(); +void enable_e(); +void do_x_step(); +void do_y_step(); +void do_z_step(); +void do_e_step(); + +void kill(byte debug); + diff --git a/Sprinter/Sprinter.pde b/Sprinter/Sprinter.pde new file mode 100644 index 0000000..4528324 --- /dev/null +++ b/Sprinter/Sprinter.pde @@ -0,0 +1,1548 @@ +// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. +// Licence: GPL + +#include "Tonokip_Firmware.h" +#include "configuration.h" +#include "pins.h" + +#ifdef SDSUPPORT +#include "SdFat.h" +#endif + +// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html +// http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes + +//Implemented Codes +//------------------- +// G0 -> G1 +// G1 - Coordinated Movement X Y Z E +// G4 - Dwell S or P +// G28 - Home all Axis +// G90 - Use Absolute Coordinates +// G91 - Use Relative Coordinates +// G92 - Set current position to cordinates given + +//RepRap M Codes +// M104 - Set extruder target temp +// M105 - Read current temp +// M106 - Fan on +// M107 - Fan off +// M109 - Wait for extruder current temp to reach target temp. +// M114 - Display current position + +//Custom M Codes +// M80 - Turn on Power Supply +// M20 - List SD card +// M21 - Init SD card +// M22 - Release SD card +// M23 - Select SD file (M23 filename.g) +// M24 - Start/resume SD print +// M25 - Pause SD print +// M26 - Set SD position in bytes (M26 S12345) +// M27 - Report SD print status +// M28 - Start SD write (M28 filename.g) +// M29 - Stop SD write +// M81 - Turn off Power Supply +// M82 - Set E codes absolute (default) +// M83 - Set E codes relative while in Absolute Coordinates (G90) mode +// M84 - Disable steppers until next move, +// or use S to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout. +// M85 - Set inactivity shutdown timer with parameter S. To disable set zero (default) +// M92 - Set axis_steps_per_unit - same syntax as G92 +// M115 - Capabilities string +// M140 - Set bed target temp +// M190 - Wait for bed current temp to reach target temp. +// M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) +// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) + + +//Stepper Movement Variables +char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; +bool move_direction[NUM_AXIS]; +const int STEP_PIN[NUM_AXIS] = {X_STEP_PIN, Y_STEP_PIN, Z_STEP_PIN, E_STEP_PIN}; +unsigned long axis_previous_micros[NUM_AXIS]; +unsigned long previous_micros = 0, previous_millis_heater, previous_millis_bed_heater; +unsigned long move_steps_to_take[NUM_AXIS]; +#ifdef RAMP_ACCELERATION + unsigned long axis_max_interval[] = {100000000.0 / (max_start_speed_units_per_second[0] * axis_steps_per_unit[0]), + 100000000.0 / (max_start_speed_units_per_second[1] * axis_steps_per_unit[1]), + 100000000.0 / (max_start_speed_units_per_second[2] * axis_steps_per_unit[2]), + 100000000.0 / (max_start_speed_units_per_second[3] * axis_steps_per_unit[3])}; //TODO: refactor all things like this in a function, or move to setup() + // in a for loop + unsigned long max_interval; + unsigned long axis_steps_per_sqr_second[] = {max_acceleration_units_per_sq_second[0] * axis_steps_per_unit[0], + max_acceleration_units_per_sq_second[1] * axis_steps_per_unit[1], max_acceleration_units_per_sq_second[2] * axis_steps_per_unit[2], + max_acceleration_units_per_sq_second[3] * axis_steps_per_unit[3]}; + unsigned long axis_travel_steps_per_sqr_second[] = {max_travel_acceleration_units_per_sq_second[0] * axis_steps_per_unit[0], + max_travel_acceleration_units_per_sq_second[1] * axis_steps_per_unit[1], max_travel_acceleration_units_per_sq_second[2] * axis_steps_per_unit[2], + max_travel_acceleration_units_per_sq_second[3] * axis_steps_per_unit[3]}; + unsigned long steps_per_sqr_second, plateau_steps; +#endif +boolean acceleration_enabled = false, accelerating = false; +unsigned long interval; +float destination[NUM_AXIS] = {0.0, 0.0, 0.0, 0.0}; +float current_position[NUM_AXIS] = {0.0, 0.0, 0.0, 0.0}; +long axis_interval[NUM_AXIS]; // for speed delay +bool home_all_axis = true; +float feedrate = 1500, next_feedrate, saved_feedrate; +float time_for_move; +long gcode_N, gcode_LastN; +bool relative_mode = false; //Determines Absolute or Relative Coordinates +bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. +long timediff = 0; +//experimental feedrate calc +float d = 0; +float axis_diff[NUM_AXIS] = {0, 0, 0, 0}; +#ifdef STEP_DELAY_RATIO + long long_step_delay_ratio = STEP_DELAY_RATIO * 100; +#endif + + +// comm variables +#define MAX_CMD_SIZE 96 +#define BUFSIZE 8 +char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; +bool fromsd[BUFSIZE]; +int bufindr = 0; +int bufindw = 0; +int buflen = 0; +int i = 0; +char serial_char; +int serial_count = 0; +boolean comment_mode = false; +char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc + +// Manage heater variables. For a thermistor or AD595 thermocouple, raw values refer to the +// reading from the analog pin. For a MAX6675 thermocouple, the raw value is the temperature in 0.25 +// degree increments (i.e. 100=25 deg). + +int target_raw = 0; +int current_raw = 0; +int target_bed_raw = 0; +int current_bed_raw = 0; +float tt = 0, bt = 0; +#ifdef PIDTEMP + int temp_iState = 0; + int temp_dState = 0; + int pTerm; + int iTerm; + int dTerm; + //int output; + int error; + int temp_iState_min = 100 * -PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; + int temp_iState_max = 100 * PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; +#endif +#ifdef SMOOTHING + uint32_t nma = SMOOTHFACTOR * analogRead(TEMP_0_PIN); +#endif +#ifdef WATCHPERIOD + int watch_raw = -1000; + unsigned long watchmillis = 0; +#endif +#ifdef MINTEMP + int minttemp = temp2analog(MINTEMP); +#endif +#ifdef MAXTEMP +int maxttemp = temp2analog(MAXTEMP); +#endif + +//Inactivity shutdown variables +unsigned long previous_millis_cmd = 0; +unsigned long max_inactive_time = 0; +unsigned long stepper_inactive_time = 0; + +#ifdef SDSUPPORT + Sd2Card card; + SdVolume volume; + SdFile root; + SdFile file; + uint32_t filesize = 0; + uint32_t sdpos = 0; + bool sdmode = false; + bool sdactive = false; + bool savetosd = false; + int16_t n; + + void initsd(){ + sdactive = false; + #if SDSS >- 1 + if(root.isOpen()) + root.close(); + if (!card.init(SPI_FULL_SPEED,SDSS)){ + //if (!card.init(SPI_HALF_SPEED,SDSS)) + Serial.println("SD init fail"); + } + else if (!volume.init(&card)) + Serial.println("volume.init failed"); + else if (!root.openRoot(&volume)) + Serial.println("openRoot failed"); + else + sdactive = true; + #endif + } + + inline void 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'; + //Serial.println(begin); + file.write(begin); + if (file.writeError){ + Serial.println("error writing to file"); + } + } +#endif + + +void setup() +{ + Serial.begin(BAUDRATE); + Serial.println("start"); + for(int i = 0; i < BUFSIZE; i++){ + fromsd[i] = false; + } + + //Initialize Step Pins + for(int i=0; i < NUM_AXIS; i++) if(STEP_PIN[i] > -1) pinMode(STEP_PIN[i],OUTPUT); + + //Initialize Dir Pins + if(X_DIR_PIN > -1) pinMode(X_DIR_PIN,OUTPUT); + if(Y_DIR_PIN > -1) pinMode(Y_DIR_PIN,OUTPUT); + if(Z_DIR_PIN > -1) pinMode(Z_DIR_PIN,OUTPUT); + if(E_DIR_PIN > -1) pinMode(E_DIR_PIN,OUTPUT); + + //Steppers default to disabled. + if(X_ENABLE_PIN > -1) if(!X_ENABLE_ON) digitalWrite(X_ENABLE_PIN,HIGH); + if(Y_ENABLE_PIN > -1) if(!Y_ENABLE_ON) digitalWrite(Y_ENABLE_PIN,HIGH); + if(Z_ENABLE_PIN > -1) if(!Z_ENABLE_ON) digitalWrite(Z_ENABLE_PIN,HIGH); + if(E_ENABLE_PIN > -1) if(!E_ENABLE_ON) digitalWrite(E_ENABLE_PIN,HIGH); + + //endstop pullups + #ifdef ENDSTOPPULLUPS + if(X_MIN_PIN > -1) { pinMode(X_MIN_PIN,INPUT); digitalWrite(X_MIN_PIN,HIGH);} + if(Y_MIN_PIN > -1) { pinMode(Y_MIN_PIN,INPUT); digitalWrite(Y_MIN_PIN,HIGH);} + if(Z_MIN_PIN > -1) { pinMode(Z_MIN_PIN,INPUT); digitalWrite(Z_MIN_PIN,HIGH);} + if(X_MAX_PIN > -1) { pinMode(X_MAX_PIN,INPUT); digitalWrite(X_MAX_PIN,HIGH);} + if(Y_MAX_PIN > -1) { pinMode(Y_MAX_PIN,INPUT); digitalWrite(Y_MAX_PIN,HIGH);} + if(Z_MAX_PIN > -1) { pinMode(Z_MAX_PIN,INPUT); digitalWrite(Z_MAX_PIN,HIGH);} + #endif + //Initialize Enable Pins + if(X_ENABLE_PIN > -1) pinMode(X_ENABLE_PIN,OUTPUT); + if(Y_ENABLE_PIN > -1) pinMode(Y_ENABLE_PIN,OUTPUT); + if(Z_ENABLE_PIN > -1) pinMode(Z_ENABLE_PIN,OUTPUT); + if(E_ENABLE_PIN > -1) pinMode(E_ENABLE_PIN,OUTPUT); + + if(HEATER_0_PIN > -1) pinMode(HEATER_0_PIN,OUTPUT); + if(HEATER_1_PIN > -1) pinMode(HEATER_1_PIN,OUTPUT); + +#ifdef HEATER_USES_MAX6675 + digitalWrite(SCK_PIN,0); + pinMode(SCK_PIN,OUTPUT); + + digitalWrite(MOSI_PIN,1); + pinMode(MOSI_PIN,OUTPUT); + + digitalWrite(MISO_PIN,1); + pinMode(MISO_PIN,INPUT); + + digitalWrite(MAX6675_SS,1); + pinMode(MAX6675_SS,OUTPUT); +#endif + +#ifdef SDSUPPORT + + //power to SD reader + #if SDPOWER > -1 + pinMode(SDPOWER,OUTPUT); + digitalWrite(SDPOWER,HIGH); + #endif + initsd(); + +#endif + +} + + +void loop() +{ + if(buflen<3) + get_command(); + + if(buflen){ +#ifdef SDSUPPORT + if(savetosd){ + if(strstr(cmdbuffer[bufindr],"M29") == NULL){ + write_command(cmdbuffer[bufindr]); + Serial.println("ok"); + }else{ + file.sync(); + file.close(); + savetosd = false; + Serial.println("Done saving file."); + } + }else{ + process_commands(); + } +#else + process_commands(); +#endif + buflen = (buflen-1); + bufindr = (bufindr + 1)%BUFSIZE; + } + //check heater every n milliseconds + manage_heater(); + manage_inactivity(1); + } + + +inline void get_command() +{ + while( Serial.available() > 0 && buflen < BUFSIZE) { + serial_char = Serial.read(); + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = false; + if(strstr(cmdbuffer[bufindw], "N") != NULL) + { + strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); + gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { + Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); + Serial.println(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if(strstr(cmdbuffer[bufindw], "*") != NULL) + { + byte checksum = 0; + byte count = 0; + while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; + strchr_pointer = strchr(cmdbuffer[bufindw], '*'); + + if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { + Serial.print("Error: checksum mismatch, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + //if no errors, continue parsing + } + else + { + Serial.print("Error: No Checksum with line number, Last Line:"); + Serial.println(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + gcode_LastN = gcode_N; + //if no errors, continue parsing + } + else // if we don't receive 'N' but still see '*' + { + if((strstr(cmdbuffer[bufindw], "*") != NULL)) + { + Serial.print("Error: No Line Number with checksum, Last Line:"); + Serial.println(gcode_LastN); + serial_count = 0; + return; + } + } + if((strstr(cmdbuffer[bufindw], "G") != NULL)){ + strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); + switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ + case 0: + case 1: + #ifdef SDSUPPORT + if(savetosd) + break; + #endif + Serial.println("ok"); + break; + default: + break; + } + + } + bufindw = (bufindw + 1)%BUFSIZE; + buflen += 1; + + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } + } +#ifdef SDSUPPORT +if(!sdmode || serial_count!=0){ + return; +} + while( filesize > sdpos && buflen < BUFSIZE) { + n = file.read(); + serial_char = (char)n; + if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) + { + sdpos = file.curPosition(); + if(sdpos >= filesize){ + sdmode = false; + Serial.println("Done printing file"); + } + if(!serial_count) return; //if empty line + cmdbuffer[bufindw][serial_count] = 0; //terminate string + if(!comment_mode){ + fromsd[bufindw] = true; + buflen += 1; + bufindw = (bufindw + 1)%BUFSIZE; + } + comment_mode = false; //for new command + serial_count = 0; //clear buffer + } + else + { + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; + } +} +#endif + +} + + +inline float code_value() { return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); } +inline long code_value_long() { return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); } +inline bool code_seen(char code_string[]) { return (strstr(cmdbuffer[bufindr], code_string) != NULL); } //Return True if the string was found + +inline bool code_seen(char code) +{ + strchr_pointer = strchr(cmdbuffer[bufindr], code); + return (strchr_pointer != NULL); //Return True if a character was found +} + +inline void process_commands() +{ + unsigned long codenum; //throw away variable + char *starpos = NULL; + + if(code_seen('G')) + { + switch((int)code_value()) + { + case 0: // G0 -> G1 + case 1: // G1 + #ifdef DISABLE_CHECK_DURING_ACC || DISABLE_CHECK_DURING_MOVE || DISABLE_CHECK_DURING_TRAVEL + manage_heater(); + #endif + get_coordinates(); // For X Y Z E F + prepare_move(); + previous_millis_cmd = millis(); + //ClearToSend(); + return; + //break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + codenum += millis(); // keep track of when we started waiting + while(millis() < codenum ){ + manage_heater(); + } + break; + case 28: //G28 Home all Axis one at a time + saved_feedrate = feedrate; + for(int i=0; i < NUM_AXIS; i++) { + destination[i] = 0; + current_position[i] = 0; + } + feedrate = 0; + + home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); + + if((home_all_axis) || (code_seen('X'))) { + if((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)) { + current_position[0] = 0; + destination[0] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; + feedrate = max_start_speed_units_per_second[0] * 60; + prepare_move(); + + current_position[0] = 0; + destination[0] = -1 * X_HOME_DIR; + prepare_move(); + + destination[0] = 10 * X_HOME_DIR; + prepare_move(); + + current_position[0] = 0; + destination[0] = 0; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen('X'))) { + if((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)) { + current_position[1] = 0; + destination[1] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; + feedrate = max_start_speed_units_per_second[1] * 60; + prepare_move(); + + current_position[1] = 0; + destination[1] = -1 * Y_HOME_DIR; + prepare_move(); + + destination[1] = 10 * Y_HOME_DIR; + prepare_move(); + + current_position[1] = 0; + destination[1] = 0; + feedrate = 0; + } + } + + if((home_all_axis) || (code_seen('X'))) { + if((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)) { + current_position[2] = 0; + destination[2] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; + feedrate = max_feedrate[2]/2; + prepare_move(); + + current_position[2] = 0; + destination[2] = -1 * Z_HOME_DIR; + prepare_move(); + + destination[2] = 10 * Z_HOME_DIR; + prepare_move(); + + current_position[2] = 0; + destination[2] = 0; + feedrate = 0; + } + } + + feedrate = saved_feedrate; + previous_millis_cmd = millis(); + break; + case 90: // G90 + relative_mode = false; + break; + case 91: // G91 + relative_mode = true; + break; + case 92: // G92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) current_position[i] = code_value(); + } + break; + + } + } + + else if(code_seen('M')) + { + + switch( (int)code_value() ) + { +#ifdef SDSUPPORT + + case 20: // M20 - list SD card + Serial.println("Begin file list"); + root.ls(); + Serial.println("End file list"); + break; + case 21: // M21 - init SD card + sdmode = false; + initsd(); + break; + case 22: //M22 - release SD card + sdmode = false; + sdactive = false; + break; + case 23: //M23 - Select file + if(sdactive){ + sdmode = false; + file.close(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos-1)='\0'; + if (file.open(&root, strchr_pointer + 4, O_READ)) { + Serial.print("File opened:"); + Serial.print(strchr_pointer + 4); + Serial.print(" Size:"); + Serial.println(file.fileSize()); + sdpos = 0; + filesize = file.fileSize(); + Serial.println("File selected"); + } + else{ + Serial.println("file.open failed"); + } + } + break; + case 24: //M24 - Start SD print + if(sdactive){ + sdmode = true; + } + break; + case 25: //M25 - Pause SD print + if(sdmode){ + sdmode = false; + } + break; + case 26: //M26 - Set SD index + if(sdactive && code_seen('S')){ + sdpos = code_value_long(); + file.seekSet(sdpos); + } + break; + case 27: //M27 - Get SD status + if(sdactive){ + Serial.print("SD printing byte "); + Serial.print(sdpos); + Serial.print("/"); + Serial.println(filesize); + }else{ + Serial.println("Not SD printing"); + } + break; + case 28: //M28 - Start SD write + if(sdactive){ + char* npos = 0; + file.close(); + sdmode = false; + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL){ + npos = strchr(cmdbuffer[bufindr], 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos-1) = '\0'; + } + if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + Serial.print("open failed, File: "); + Serial.print(strchr_pointer + 4); + Serial.print("."); + }else{ + savetosd = true; + Serial.print("Writing to file: "); + Serial.println(strchr_pointer + 4); + } + } + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //savetosd = false; + break; +#endif + case 104: // M104 + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw > current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + break; + case 140: // M140 set bed temp + if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); + break; + case 105: // M105 + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) + tt = analog2temp(current_raw); + #endif + #if TEMP_1_PIN > -1 + bt = analog2tempBed(current_bed_raw); + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) + Serial.print("ok T:"); + Serial.print(tt); + #if TEMP_1_PIN > -1 + Serial.print(" B:"); + Serial.println(bt); + #else + Serial.println(); + #endif + #else + Serial.println("No thermistors - no temp"); + #endif + return; + //break; + case 109: // M109 - Wait for extruder heater to reach target. + if (code_seen('S')) target_raw = temp2analog(code_value()); + #ifdef WATCHPERIOD + if(target_raw>current_raw){ + watchmillis = max(1,millis()); + watch_raw = current_raw; + }else{ + watchmillis = 0; + } + #endif + codenum = millis(); + while(current_raw < target_raw) { + if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + Serial.print("T:"); + Serial.println( analog2temp(current_raw) ); + codenum = millis(); + } + manage_heater(); + } + break; + case 190: // M190 - Wait bed for heater to reach target. + #if TEMP_1_PIN > -1 + if (code_seen('S')) target_bed_raw = temp2analog(code_value()); + codenum = millis(); + while(current_bed_raw < target_bed_raw) { + if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + tt=analog2temp(current_raw); + Serial.print("T:"); + Serial.println( tt ); + Serial.print("ok T:"); + Serial.print( tt ); + Serial.print(" B:"); + Serial.println( analog2temp(current_bed_raw) ); + codenum = millis(); + } + manage_heater(); + } + #endif + break; + case 106: //M106 Fan On + if (code_seen('S')){ + digitalWrite(FAN_PIN, HIGH); + analogWrite(FAN_PIN, constrain(code_value(),0,255) ); + } + else + digitalWrite(FAN_PIN, HIGH); + break; + case 107: //M107 Fan Off + analogWrite(FAN_PIN, 0); + + digitalWrite(FAN_PIN, LOW); + break; + case 80: // M81 - ATX Power On + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,OUTPUT); //GND + break; + case 81: // M81 - ATX Power Off + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); //Floating + break; + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 84: + if(code_seen('S')){ stepper_inactive_time = code_value() * 1000; } + else{ disable_x(); disable_y(); disable_z(); disable_e(); } + break; + case 85: // M85 + code_seen('S'); + max_inactive_time = code_value() * 1000; + break; + case 92: // M92 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); + } + + //Update start speed intervals and axis order. TODO: refactor axis_max_interval[] calculation into a function, as it + // should also be used in setup() as well + #ifdef RAMP_ACCELERATION + long temp_max_intervals[NUM_AXIS]; + for(int i=0; i < NUM_AXIS; i++) { + axis_max_interval[i] = 100000000.0 / (max_start_speed_units_per_second[i] * axis_steps_per_unit[i]);//TODO: do this for + // all steps_per_unit related variables + } + #endif + break; + case 115: // M115 + Serial.println("FIRMWARE_NAME:Sprinter FIRMWARE_URL:http%%3A/github.com/kliment/Sprinter/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); + break; + case 114: // M114 + Serial.print("X:"); + Serial.print(current_position[0]); + Serial.print("Y:"); + Serial.print(current_position[1]); + Serial.print("Z:"); + Serial.print(current_position[2]); + Serial.print("E:"); + Serial.println(current_position[3]); + break; + #ifdef RAMP_ACCELERATION + //TODO: update for all axis, use for loop + case 201: // M201 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; + case 202: // M202 + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; + } + break; + #endif + } + + } + else{ + Serial.println("Unknown command:"); + Serial.println(cmdbuffer[bufindr]); + } + + ClearToSend(); + +} + +inline void FlushSerialRequestResend() +{ + //char cmdbuffer[bufindr][100]="Resend:"; + Serial.flush(); + Serial.print("Resend:"); + Serial.println(gcode_LastN + 1); + ClearToSend(); +} + +inline void ClearToSend() +{ + previous_millis_cmd = millis(); + #ifdef SDSUPPORT + if(fromsd[bufindr]) + return; + #endif + Serial.println("ok"); +} + +inline void get_coordinates() +{ + for(int i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; + else destination[i] = current_position[i]; //Are these else lines really needed? + } + if(code_seen('F')) { + next_feedrate = code_value(); + if(next_feedrate > 0.0) feedrate = next_feedrate; + } +} + +inline void prepare_move() +{ + //Find direction + for(int i=0; i < NUM_AXIS; i++) { + if(destination[i] >= current_position[i]) move_direction[i] = 1; + else move_direction[i] = 0; + } + + + if (min_software_endstops) { + if (destination[0] < 0) destination[0] = 0.0; + if (destination[1] < 0) destination[1] = 0.0; + if (destination[2] < 0) destination[2] = 0.0; + } + + if (max_software_endstops) { + if (destination[0] > X_MAX_LENGTH) destination[0] = X_MAX_LENGTH; + if (destination[1] > Y_MAX_LENGTH) destination[1] = Y_MAX_LENGTH; + if (destination[2] > Z_MAX_LENGTH) destination[2] = Z_MAX_LENGTH; + } + + for(int i=0; i < NUM_AXIS; i++) { + axis_diff[i] = destination[i] - current_position[i]; + move_steps_to_take[i] = abs(axis_diff[i]) * axis_steps_per_unit[i]; + } + if(feedrate < 10) + feedrate = 10; + + //Feedrate calc based on XYZ travel distance + float xy_d; + if(abs(axis_diff[0]) > 0 || abs(axis_diff[1]) > 0 || abs(axis_diff[2])) { + xy_d = sqrt(axis_diff[0] * axis_diff[0] + axis_diff[1] * axis_diff[1]); + d = sqrt(xy_d * xy_d + axis_diff[2] * axis_diff[2]); + } + else if(abs(axis_diff[3]) > 0) + d = abs(axis_diff[3]); + #ifdef DEBUG_PREPARE_MOVE + else { + log_message("_PREPARE_MOVE - No steps to take!"); + } + #endif + time_for_move = (d / (feedrate / 60000000.0) ); + //Check max feedrate for each axis is not violated, update time_for_move if necessary + for(int i = 0; i < NUM_AXIS; i++) { + if(move_steps_to_take[i] && abs(axis_diff[i]) / (time_for_move / 60000000.0) > max_feedrate[i]) { + time_for_move = time_for_move / max_feedrate[i] * (abs(axis_diff[i]) / (time_for_move / 60000000.0)); + } + } + //Calculate the full speed stepper interval for each axis + for(int i=0; i < NUM_AXIS; i++) { + if(move_steps_to_take[i]) axis_interval[i] = time_for_move / move_steps_to_take[i] * 100; + } + + #ifdef DEBUG_PREPARE_MOVE + log_float("_PREPARE_MOVE - Move distance on the XY plane", xy_d); + log_float("_PREPARE_MOVE - Move distance on the XYZ space", d); + log_float("_PREPARE_MOVE - Commanded feedrate", feedrate); + log_float("_PREPARE_MOVE - Constant full speed move time", time_for_move); + log_float_array("_PREPARE_MOVE - Destination", destination, NUM_AXIS); + log_float_array("_PREPARE_MOVE - Current position", current_position, NUM_AXIS); + log_ulong_array("_PREPARE_MOVE - Steps to take", move_steps_to_take, NUM_AXIS); + log_long_array("_PREPARE_MOVE - Axes full speed intervals", axis_interval, NUM_AXIS); + #endif + + unsigned long move_steps[NUM_AXIS]; + for(int i=0; i < NUM_AXIS; i++) + move_steps[i] = move_steps_to_take[i]; + linear_move(move_steps); // make the move +} + +void linear_move(unsigned long axis_steps_remaining[]) // make linear move with preset speeds and destinations, see G0 and G1 +{ + //Determine direction of movement + if (destination[0] > current_position[0]) digitalWrite(X_DIR_PIN,!INVERT_X_DIR); + else digitalWrite(X_DIR_PIN,INVERT_X_DIR); + if (destination[1] > current_position[1]) digitalWrite(Y_DIR_PIN,!INVERT_Y_DIR); + else digitalWrite(Y_DIR_PIN,INVERT_Y_DIR); + if (destination[2] > current_position[2]) digitalWrite(Z_DIR_PIN,!INVERT_Z_DIR); + else digitalWrite(Z_DIR_PIN,INVERT_Z_DIR); + if (destination[3] > current_position[3]) digitalWrite(E_DIR_PIN,!INVERT_E_DIR); + else digitalWrite(E_DIR_PIN,INVERT_E_DIR); + + if(X_MIN_PIN > -1) if(!move_direction[0]) if(digitalRead(X_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[0]=0; + if(Y_MIN_PIN > -1) if(!move_direction[1]) if(digitalRead(Y_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[1]=0; + if(Z_MIN_PIN > -1) if(!move_direction[2]) if(digitalRead(Z_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[2]=0; + if(X_MAX_PIN > -1) if(move_direction[0]) if(digitalRead(X_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[0]=0; + if(Y_MAX_PIN > -1) if(move_direction[1]) if(digitalRead(Y_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[1]=0; + if(Z_MAX_PIN > -1) if(move_direction[2]) if(digitalRead(Z_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[2]=0; + + + //Only enable axis that are moving. If the axis doesn't need to move then it can stay disabled depending on configuration. + // TODO: maybe it's better to refactor into a generic enable(int axis) function, that will probably take more ram, + // but will reduce code size + if(axis_steps_remaining[0]) enable_x(); + if(axis_steps_remaining[1]) enable_y(); + if(axis_steps_remaining[2]) enable_z(); + if(axis_steps_remaining[3]) enable_e(); + + //Define variables that are needed for the Bresenham algorithm. Please note that Z is not currently included in the Bresenham algorithm. + unsigned long delta[] = {axis_steps_remaining[0], axis_steps_remaining[1], axis_steps_remaining[2], axis_steps_remaining[3]}; //TODO: implement a "for" to support N axes + long axis_error[NUM_AXIS]; + unsigned int primary_axis; + if(delta[1] > delta[0] && delta[1] > delta[2] && delta[1] > delta[3]) primary_axis = 1; + else if (delta[0] >= delta[1] && delta[0] > delta[2] && delta[0] > delta[3]) primary_axis = 0; + else if (delta[2] >= delta[0] && delta[2] >= delta[1] && delta[2] > delta[3]) primary_axis = 2; + else primary_axis = 3; + unsigned long steps_remaining = delta[primary_axis]; + unsigned long steps_to_take = steps_remaining; + for(int i=0; i < NUM_AXIS; i++) if(i != primary_axis) axis_error[i] = delta[primary_axis] / 2; + interval = axis_interval[primary_axis]; + bool is_print_move = delta[3] > 0; + #ifdef DEBUG_BRESENHAM + log_int("_BRESENHAM - Primary axis", primary_axis); + log_int("_BRESENHAM - Primary axis full speed interval", interval); + log_ulong_array("_BRESENHAM - Deltas", delta, NUM_AXIS); + log_long_array("_BRESENHAM - Errors", axis_error, NUM_AXIS); + #endif + + //If acceleration is enabled, do some Bresenham calculations depending on which axis will lead it. + #ifdef RAMP_ACCELERATION + long max_speed_steps_per_second; + long min_speed_steps_per_second; + max_interval = axis_max_interval[primary_axis]; + #ifdef DEBUG_RAMP_ACCELERATION + log_ulong_array("_RAMP_ACCELERATION - Teoric step intervals at move start", axis_max_interval, NUM_AXIS); + #endif + unsigned long new_axis_max_intervals[NUM_AXIS]; + max_speed_steps_per_second = 100000000 / interval; + min_speed_steps_per_second = 100000000 / max_interval; //TODO: can this be deleted? + //Calculate start speeds based on moving axes max start speed constraints. + int slowest_start_axis = primary_axis; + unsigned long slowest_start_axis_max_interval = max_interval; + for(int i = 0; i < NUM_AXIS; i++) + if (axis_steps_remaining[i] >0 && i != primary_axis && axis_max_interval[i] * axis_steps_remaining[i] + / axis_steps_remaining[slowest_start_axis] > slowest_start_axis_max_interval) { + slowest_start_axis = i; + slowest_start_axis_max_interval = axis_max_interval[i]; + } + for(int i = 0; i < NUM_AXIS; i++) + if(axis_steps_remaining[i] >0) { + new_axis_max_intervals[i] = slowest_start_axis_max_interval * axis_steps_remaining[slowest_start_axis] / axis_steps_remaining[i]; + if(i == primary_axis) { + max_interval = new_axis_max_intervals[i]; + min_speed_steps_per_second = 100000000 / max_interval; + } + } + //Calculate slowest axis plateau time + float slowest_axis_plateau_time = 0; + for(int i=0; i < NUM_AXIS ; i++) { + if(axis_steps_remaining[i] > 0) { + if(is_print_move && axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, + (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_steps_per_sqr_second[i]); + else if(axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, + (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_travel_steps_per_sqr_second[i]); + } + } + //Now we can calculate the new primary axis acceleration, so that the slowest axis max acceleration is not violated + steps_per_sqr_second = (100000000.0 / axis_interval[primary_axis] - 100000000.0 / new_axis_max_intervals[primary_axis]) / slowest_axis_plateau_time; + plateau_steps = (long) ((steps_per_sqr_second / 2.0 * slowest_axis_plateau_time + min_speed_steps_per_second) * slowest_axis_plateau_time); + #ifdef DEBUG_RAMP_ACCELERATION + log_int("_RAMP_ACCELERATION - Start speed limiting axis", slowest_start_axis); + log_ulong("_RAMP_ACCELERATION - Limiting axis start interval", slowest_start_axis_max_interval); + log_ulong_array("_RAMP_ACCELERATION - Actual step intervals at move start", new_axis_max_intervals, NUM_AXIS); + #endif + #endif + + unsigned long steps_done = 0; + #ifdef RAMP_ACCELERATION + plateau_steps *= 1.01; // This is to compensate we use discrete intervals + acceleration_enabled = true; + long full_interval = interval; + if(interval > max_interval) acceleration_enabled = false; + boolean decelerating = false; + #endif + + unsigned long start_move_micros = micros(); + for(int i = 0; i < NUM_AXIS; i++) { + axis_previous_micros[i] = start_move_micros * 100; + } + + #ifdef DISABLE_CHECK_DURING_TRAVEL + //If the move time is more than allowed in DISABLE_CHECK_DURING_TRAVEL, let's + // consider this a print move and perform heat management during it + if(time_for_move / 1000 > DISABLE_CHECK_DURING_TRAVEL) is_print_move = true; + //else, if the move is a retract, consider it as a travel move for the sake of this feature + else if(delta[3]>0 && delta[0] + delta[1] + delta[2] == 0) is_print_move = false; + #ifdef DEBUG_DISABLE_CHECK_DURING_TRAVEL + log_bool("_DISABLE_CHECK_DURING_TRAVEL - is_print_move", is_print_move); + #endif + #endif + + #ifdef DEBUG_MOVE_TIME + unsigned long startmove = micros(); + #endif + + //move until no more steps remain + while(axis_steps_remaining[0] + axis_steps_remaining[1] + axis_steps_remaining[2] + axis_steps_remaining[3] > 0) { + #ifdef DISABLE_CHECK_DURING_ACC + if(!accelerating && !decelerating) { + //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp + #ifdef DISABLE_CHECK_DURING_TRAVEL + if(is_print_move) + #endif + manage_heater(); + } + #else + #ifdef DISABLE_CHECK_DURING_MOVE + {} //Do nothing + #else + //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp + #ifdef DISABLE_CHECK_DURING_TRAVEL + if(is_print_move) + #endif + manage_heater(); + #endif + #endif + #ifdef RAMP_ACCELERATION + //If acceleration is enabled on this move and we are in the acceleration segment, calculate the current interval + if (acceleration_enabled && steps_done == 0) { + interval = max_interval; + } else if (acceleration_enabled && steps_done <= plateau_steps) { + long current_speed = (long) ((((long) steps_per_sqr_second) / 10000) + * ((micros() - start_move_micros) / 100) + (long) min_speed_steps_per_second); + interval = 100000000 / current_speed; + if (interval < full_interval) { + accelerating = false; + interval = full_interval; + } + if (steps_done >= steps_to_take / 2) { + plateau_steps = steps_done; + max_speed_steps_per_second = 100000000 / interval; + accelerating = false; + } + } else if (acceleration_enabled && steps_remaining <= plateau_steps) { //(interval > minInterval * 100) { + if (!accelerating) { + start_move_micros = micros(); + accelerating = true; + decelerating = true; + } + long current_speed = (long) ((long) max_speed_steps_per_second - ((((long) steps_per_sqr_second) / 10000) + * ((micros() - start_move_micros) / 100))); + interval = 100000000 / current_speed; + if (interval > max_interval) + interval = max_interval; + } else { + //Else, we are just use the full speed interval as current interval + interval = full_interval; + accelerating = false; + } + #endif + + //If there are x or y steps remaining, perform Bresenham algorithm + if(axis_steps_remaining[primary_axis]) { + if(X_MIN_PIN > -1) if(!move_direction[0]) if(digitalRead(X_MIN_PIN) != ENDSTOPS_INVERTING) break; + if(Y_MIN_PIN > -1) if(!move_direction[1]) if(digitalRead(Y_MIN_PIN) != ENDSTOPS_INVERTING) break; + if(X_MAX_PIN > -1) if(move_direction[0]) if(digitalRead(X_MAX_PIN) != ENDSTOPS_INVERTING) break; + if(Y_MAX_PIN > -1) if(move_direction[1]) if(digitalRead(Y_MAX_PIN) != ENDSTOPS_INVERTING) break; + if(Z_MIN_PIN > -1) if(!move_direction[2]) if(digitalRead(Z_MIN_PIN) != ENDSTOPS_INVERTING) break; + if(Z_MAX_PIN > -1) if(move_direction[2]) if(digitalRead(Z_MAX_PIN) != ENDSTOPS_INVERTING) break; + timediff = micros() * 100 - axis_previous_micros[primary_axis]; + while(timediff >= interval && axis_steps_remaining[primary_axis] > 0) { + steps_done++; + steps_remaining--; + axis_steps_remaining[primary_axis]--; timediff -= interval; + do_step_update_micros(primary_axis); + for(int i=0; i < NUM_AXIS; i++) if(i != primary_axis && axis_steps_remaining[i] > 0) { + axis_error[i] = axis_error[i] - delta[i]; + if(axis_error[i] < 0) { + do_step(i); axis_steps_remaining[i]--; + axis_error[i] = axis_error[i] + delta[primary_axis]; + } + } + #ifdef STEP_DELAY_RATIO + if(timediff >= interval) delayMicroseconds(long_step_delay_ratio * interval / 10000); + #endif + #ifdef STEP_DELAY_MICROS + if(timediff >= interval) delayMicroseconds(STEP_DELAY_MICROS); + #endif + } + } + } + #ifdef DEBUG_MOVE_TIME + log_ulong("_MOVE_TIME - This move took", micros()-startmove); + #endif + + if(DISABLE_X) disable_x(); + if(DISABLE_Y) disable_y(); + if(DISABLE_Z) disable_z(); + if(DISABLE_E) disable_e(); + + // Update current position partly based on direction, we probably can combine this with the direction code above... + for(int i=0; i < NUM_AXIS; i++) { + if (destination[i] > current_position[i]) current_position[i] = current_position[i] + move_steps_to_take[i] / axis_steps_per_unit[i]; + else current_position[i] = current_position[i] - move_steps_to_take[i] / axis_steps_per_unit[i]; + } +} + +inline void do_step_update_micros(int axis) { + digitalWrite(STEP_PIN[axis], HIGH); + axis_previous_micros[axis] += interval; + digitalWrite(STEP_PIN[axis], LOW); +} + +inline void do_step(int axis) { + digitalWrite(STEP_PIN[axis], HIGH); + digitalWrite(STEP_PIN[axis], LOW); +} + +inline void disable_x() { if(X_ENABLE_PIN > -1) digitalWrite(X_ENABLE_PIN,!X_ENABLE_ON); } +inline void disable_y() { if(Y_ENABLE_PIN > -1) digitalWrite(Y_ENABLE_PIN,!Y_ENABLE_ON); } +inline void disable_z() { if(Z_ENABLE_PIN > -1) digitalWrite(Z_ENABLE_PIN,!Z_ENABLE_ON); } +inline void disable_e() { if(E_ENABLE_PIN > -1) digitalWrite(E_ENABLE_PIN,!E_ENABLE_ON); } +inline void enable_x() { if(X_ENABLE_PIN > -1) digitalWrite(X_ENABLE_PIN, X_ENABLE_ON); } +inline void enable_y() { if(Y_ENABLE_PIN > -1) digitalWrite(Y_ENABLE_PIN, Y_ENABLE_ON); } +inline void enable_z() { if(Z_ENABLE_PIN > -1) digitalWrite(Z_ENABLE_PIN, Z_ENABLE_ON); } +inline void enable_e() { if(E_ENABLE_PIN > -1) digitalWrite(E_ENABLE_PIN, E_ENABLE_ON); } + +#define HEAT_INTERVAL 250 +#ifdef HEATER_USES_MAX6675 +unsigned long max6675_previous_millis = 0; +int max6675_temp = 2000; + +inline int read_max6675() +{ + if (millis() - max6675_previous_millis < HEAT_INTERVAL) + return max6675_temp; + + max6675_previous_millis = millis(); + + max6675_temp = 0; + + #ifdef PRR + PRR &= ~(1<> 3; + } + + return max6675_temp; +} +#endif + + +inline void manage_heater() +{ + if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) + return; + previous_millis_heater = millis(); + #ifdef HEATER_USES_THERMISTOR + current_raw = analogRead(TEMP_0_PIN); + #ifdef DEBUG_HEAT_MGMT + log_int("_HEAT_MGMT - analogRead(TEMP_0_PIN)", current_raw); + log_int("_HEAT_MGMT - NUMTEMPS", NUMTEMPS); + #endif + // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_raw = 1023 - current_raw; + #elif defined HEATER_USES_AD595 + current_raw = analogRead(TEMP_0_PIN); + #elif defined HEATER_USES_MAX6675 + current_raw = read_max6675(); + #endif + #ifdef SMOOTHING + nma = (nma + current_raw) - (nma / SMOOTHFACTOR); + current_raw = nma / SMOOTHFACTOR; + #endif + #ifdef WATCHPERIOD + if(watchmillis && millis() - watchmillis > WATCHPERIOD){ + if(watch_raw + 1 >= current_raw){ + target_raw = 0; + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + }else{ + watchmillis = 0; + } + } + #endif + #ifdef MINTEMP + if(current_raw <= minttemp) + target_raw = 0; + #endif + #ifdef MAXTEMP + if(current_raw >= maxttemp) { + target_raw = 0; + } + #endif + #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) + #ifdef PIDTEMP + error = target_raw - current_raw; + pTerm = (PID_PGAIN * error) / 100; + temp_iState += error; + temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); + iTerm = (PID_IGAIN * temp_iState) / 100; + dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; + temp_dState = current_raw; + analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); + #else + if(current_raw >= target_raw) + { + digitalWrite(HEATER_0_PIN,LOW); + digitalWrite(LED_PIN,LOW); + } + else + { + digitalWrite(HEATER_0_PIN,HIGH); + digitalWrite(LED_PIN,HIGH); + } + #endif + #endif + + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); + + #ifdef BED_USES_THERMISTOR + + current_bed_raw = analogRead(TEMP_1_PIN); + #ifdef DEBUG_HEAT_MGMT + log_int("_HEAT_MGMT - analogRead(TEMP_1_PIN)", current_bed_raw); + log_int("_HEAT_MGMT - BNUMTEMPS", BNUMTEMPS); + #endif + + // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, + // this switches it up so that the reading appears lower than target for the control logic. + current_bed_raw = 1023 - current_bed_raw; + #elif defined BED_USES_AD595 + current_bed_raw = analogRead(TEMP_1_PIN); + + #endif + + + #if TEMP_1_PIN > -1 + if(current_bed_raw >= target_bed_raw) + { + digitalWrite(HEATER_1_PIN,LOW); + } + else + { + digitalWrite(HEATER_1_PIN,HIGH); + } + #endif +} + +// Takes hot end temperature value as input and returns corresponding raw value. +// For a thermistor, it uses the RepRap thermistor temp table. +// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. +// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. +float temp2analog(int celsius) { + #ifdef HEATER_USES_THERMISTOR + int raw = 0; + byte i; + + for (i=1; i raw) + { + celsius = temptable[i-1][1] + + (raw - temptable[i-1][0]) * + (temptable[i][1] - temptable[i-1][1]) / + (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = temptable[i-1][1]; + + return celsius; + #elif defined HEATER_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #elif defined HEATER_USES_MAX6675 + return raw * 0.25; + #endif +} + +// Derived from RepRap FiveD extruder::getTemperature() +// For bed temperature measurement. +float analog2tempBed(int raw) { + #ifdef BED_USES_THERMISTOR + int celsius = 0; + byte i; + + raw = 1023 - raw; + + for (i=1; i raw) + { + celsius = bedtemptable[i-1][1] + + (raw - bedtemptable[i-1][0]) * + (bedtemptable[i][1] - bedtemptable[i-1][1]) / + (bedtemptable[i][0] - bedtemptable[i-1][0]); + + break; + } + } + + // Overflow: Set to last value in the table + if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; + + return celsius; + + #elif defined BED_USES_AD595 + return raw * ((5.0 * 100.0) / 1024.0); + #endif +} + +inline void kill() +{ + #if TEMP_0_PIN > -1 + target_raw=0; + digitalWrite(HEATER_0_PIN,LOW); + #endif + #if TEMP_1_PIN > -1 + target_bed_raw=0; + if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); + #endif + disable_x(); + disable_y(); + disable_z(); + disable_e(); + + if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); + +} + +inline void manage_inactivity(byte debug) { +if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); +if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { disable_x(); disable_y(); disable_z(); disable_e(); } +} + +#ifdef DEBUG +void log_message(char* message) { + Serial.print("DEBUG"); Serial.println(message); +} + +void log_bool(char* message, bool value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_int(char* message, int value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_long(char* message, long value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_float(char* message, float value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_uint(char* message, unsigned int value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_ulong(char* message, unsigned long value) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); +} + +void log_int_array(char* message, int value[], int array_lenght) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); + for(int i=0; i < array_lenght; i++){ + Serial.print(value[i]); + if(i != array_lenght-1) Serial.print(", "); + } + Serial.println("}"); +} + +void log_long_array(char* message, long value[], int array_lenght) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); + for(int i=0; i < array_lenght; i++){ + Serial.print(value[i]); + if(i != array_lenght-1) Serial.print(", "); + } + Serial.println("}"); +} + +void log_float_array(char* message, float value[], int array_lenght) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); + for(int i=0; i < array_lenght; i++){ + Serial.print(value[i]); + if(i != array_lenght-1) Serial.print(", "); + } + Serial.println("}"); +} + +void log_uint_array(char* message, unsigned int value[], int array_lenght) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); + for(int i=0; i < array_lenght; i++){ + Serial.print(value[i]); + if(i != array_lenght-1) Serial.print(", "); + } + Serial.println("}"); +} + +void log_ulong_array(char* message, unsigned long value[], int array_lenght) { + Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); + for(int i=0; i < array_lenght; i++){ + Serial.print(value[i]); + if(i != array_lenght-1) Serial.print(", "); + } + Serial.println("}"); +} +#endif diff --git a/Sprinter/ThermistorTable_100k.h b/Sprinter/ThermistorTable_100k.h new file mode 100644 index 0000000..d0698b2 --- /dev/null +++ b/Sprinter/ThermistorTable_100k.h @@ -0,0 +1,85 @@ +#ifndef THERMISTORTABLE_H_ +#define THERMISTORTABLE_H_ + +// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) +// See this page: +// http://dev.www.reprap.org/bin/view/Main/Thermistor +// for details of what goes in this table. +// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 + +#define NUMTEMPS 61 +const short temptable[NUMTEMPS][2] = { +{ 23 , 300 }, +{ 25 , 295 }, +{ 27 , 290 }, +{ 28 , 285 }, +{ 31 , 280 }, +{ 33 , 275 }, +{ 35 , 270 }, +{ 38 , 265 }, +{ 41 , 260 }, +{ 44 , 255 }, +{ 48 , 250 }, +{ 52 , 245 }, +{ 56 , 240 }, +{ 61 , 235 }, +{ 66 , 230 }, +{ 71 , 225 }, +{ 78 , 220 }, +{ 84 , 215 }, +{ 92 , 210 }, +{ 100 , 205 }, +{ 109 , 200 }, +{ 120 , 195 }, +{ 131 , 190 }, +{ 143 , 185 }, +{ 156 , 180 }, +{ 171 , 175 }, +{ 187 , 170 }, +{ 205 , 165 }, +{ 224 , 160 }, +{ 245 , 155 }, +{ 268 , 150 }, +{ 293 , 145 }, +{ 320 , 140 }, +{ 348 , 135 }, +{ 379 , 130 }, +{ 411 , 125 }, +{ 445 , 120 }, +{ 480 , 115 }, +{ 516 , 110 }, +{ 553 , 105 }, +{ 591 , 100 }, +{ 628 , 95 }, +{ 665 , 90 }, +{ 702 , 85 }, +{ 737 , 80 }, +{ 770 , 75 }, +{ 801 , 70 }, +{ 830 , 65 }, +{ 857 , 60 }, +{ 881 , 55 }, +{ 903 , 50 }, +{ 922 , 45 }, +{ 939 , 40 }, +{ 954 , 35 }, +{ 966 , 30 }, +{ 977 , 25 }, +{ 985 , 20 }, +{ 993 , 15 }, +{ 999 , 10 }, +{ 1004 , 5 }, +{ 1008 , 0 }, + +}; + + +#endif + diff --git a/Sprinter/ThermistorTable_200k.h b/Sprinter/ThermistorTable_200k.h new file mode 100644 index 0000000..4142eb2 --- /dev/null +++ b/Sprinter/ThermistorTable_200k.h @@ -0,0 +1,42 @@ +#ifndef THERMISTORTABLE_H_ +#define THERMISTORTABLE_H_ + +// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) +// See this page: +// http://dev.www.reprap.org/bin/view/Main/Thermistor +// for details of what goes in this table. +// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 +// r0: 100000 +// t0: 25 +// r1: 0 +// r2: 4700 +// beta: 4066 +// max adc: 1023 + +#define NUMTEMPS 20 +const short temptable[NUMTEMPS][2] = { + {1, 848}, + {54, 275}, + {107, 228}, + {160, 202}, + {213, 185}, + {266, 171}, + {319, 160}, + {372, 150}, + {425, 141}, + {478, 133}, + {531, 125}, + {584, 118}, + {637, 110}, + {690, 103}, + {743, 95}, + {796, 86}, + {849, 77}, + {902, 65}, + {955, 49}, + {1008, 17} +}; + + +#endif diff --git a/Sprinter/ThermistorTable_mendelparts.h b/Sprinter/ThermistorTable_mendelparts.h new file mode 100644 index 0000000..9e65b85 --- /dev/null +++ b/Sprinter/ThermistorTable_mendelparts.h @@ -0,0 +1,45 @@ +#ifndef THERMISTORTABLE_H_ +#define THERMISTORTABLE_H_ + +//thermistor table for mendel-parts thermistor +// Standardized R/T characteristic no. 8404 + // RS thermistor 484-0183; EPCOS NTC + // Mendel-Parts thermistor G540 / G550 + // Optimized for 100...300C working range. + // Max range: -20...300C + // Max reading error on Gen 6 electronics: ~+5%, -3% in 100 - 300C range. + +#define NUMTEMPS 28 +const short temptable[NUMTEMPS][2] = { + {1,864}, + {21,300}, + {25,290}, + {29,280}, + {33,270}, + {39,260}, + {46,250}, + {54,240}, + {64,230}, + {75,220}, + {90,210}, + {107,200}, + {128,190}, + {154,180}, + {184,170}, + {221,160}, + {265,150}, + {316,140}, + {375,130}, + {441,120}, + {513,110}, + {588,100}, + {734,80}, + {856,60}, + {938,40}, + {986,20}, + {1008,0}, + {1018,-20} + }; + + +#endif diff --git a/Sprinter/configuration.h b/Sprinter/configuration.h new file mode 100644 index 0000000..0a38a6a --- /dev/null +++ b/Sprinter/configuration.h @@ -0,0 +1,158 @@ +#ifndef PARAMETERS_H +#define PARAMETERS_H + +// NO RS485/EXTRUDER CONTROLLER SUPPORT +// PLEASE VERIFY PIN ASSIGNMENTS FOR YOUR CONFIGURATION!!!!!!! +#define MOTHERBOARD 3 // ATMEGA168 = 0, SANGUINO = 1, MOTHERBOARD = 2, MEGA/RAMPS = 3, ATMEGA328 = 4, Gen6 = 5, Sanguinololu = 6 + +//Comment out to disable SD support +#define SDSUPPORT 1 + +//Min step delay in microseconds. If you are experiencing missing steps, try to raise the delay microseconds, but be aware this +// If you enable this, make sure STEP_DELAY_RATIO is disabled. +//#define STEP_DELAY_MICROS 1 + +//Step delay over interval ratio. If you are still experiencing missing steps, try to uncomment the following line, but be aware this +//If you enable this, make sure STEP_DELAY_MICROS is disabled. +//#define STEP_DELAY_RATIO 0.25 + +//Comment this to disable ramp acceleration +#define RAMP_ACCELERATION 1 + +//Acceleration settings +#ifdef RAMP_ACCELERATION +//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 max_start_speed_units_per_second[] = {25.0,25.0,0.2,10.0}; +long max_acceleration_units_per_sq_second[] = {1000,1000,50,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts +long max_travel_acceleration_units_per_sq_second[] = {500,500,50}; // X, Y, Z max acceleration in mm/s^2 for travel moves +#endif + +// AD595 THERMOCOUPLE SUPPORT UNTESTED... USE WITH CAUTION!!!! + +//PID settings: +//Uncomment the following line to enable PID support. This is untested and could be disastrous. Be careful. +//#define PIDTEMP 1 +#ifdef PIDTEMP +#define PID_MAX 255 // limits current to nozzle +#define PID_INTEGRAL_DRIVE_MAX 220 +#define PID_PGAIN 180 //100 is 1.0 +#define PID_IGAIN 2 //100 is 1.0 +#define PID_DGAIN 100 //100 is 1.0 +#endif + +//How often should the heater check for new temp readings, in milliseconds +#define HEATER_CHECK_INTERVAL 500 +#define BED_CHECK_INTERVAL 5000 +//Comment the following line to enable heat management during acceleration +#define DISABLE_CHECK_DURING_ACC +#ifndef DISABLE_CHECK_DURING_ACC + //Uncomment the following line to disable heat management during the move + //#define DISABLE_CHECK_DURING_MOVE +#endif +//Uncomment the following line to disable heat management during travel moves (and extruder-only moves, eg: retracts), strongly recommended if you are missing steps mid print. +//Probably this should remain commented if are using PID. +//It also defines the max milliseconds interval after which a travel move is not considered so for the sake of this feature. +#define DISABLE_CHECK_DURING_TRAVEL 1000 + +//Experimental temperature smoothing - only uncomment this if your temp readings are noisy +//#define SMOOTHING 1 +//#define SMOOTHFACTOR 16 //best to use a power of two here - determines how many values are averaged together by the smoothing algorithm + +//Experimental watchdog and minimal temp +//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 +//The minimal temperature defines the temperature below which the heater will not be enabled +//#define MINTEMP + +//Experimental max temp +//When temperature exceeds max temp, your bot will halt. +//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 + +// Select one of these only to define how the nozzle temp is read. +#define HEATER_USES_THERMISTOR +//#define HEATER_USES_AD595 +//#define HEATER_USES_MAX6675 + +// Select one of these only to define how the bed temp is read. +#define BED_USES_THERMISTOR +//#define BED_USES_AD595 + +// Calibration formulas +// e_extruded_steps_per_mm = e_feedstock_steps_per_mm * (desired_extrusion_diameter^2 / feedstock_diameter^2) +// new_axis_steps_per_mm = previous_axis_steps_per_mm * (test_distance_instructed/test_distance_traveled) +// units are in millimeters or whatever length unit you prefer: inches,football-fields,parsecs etc + +//Calibration variables +const int NUM_AXIS = 4; // The axis order in all axis related arrays is X, Y, Z, E +bool axis_relative_modes[] = {false, false, false, false}; +float axis_steps_per_unit[] = {80.376,80.376,3200/1.25,16}; // {X steps per unit, Y steps per unit, Z steps per unit, E steps per unit} +//For SAE Prusa mendeel float z_steps_per_unit = should be 3200/1.411 for 5/16-18 rod and 3200/1.058 for 5/16-24 +//float axis_steps_per_unit[] = {10.047,10.047,833.398,0.706}; +float max_feedrate[] = {200000, 200000, 240, 500000}; //mmm, acceleration! + +//For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 +const bool X_ENABLE_ON = 0; +const bool Y_ENABLE_ON = 0; +const bool Z_ENABLE_ON = 0; +const bool E_ENABLE_ON = 0; + +//Disables axis when it's not being used. +const bool DISABLE_X = false; +const bool DISABLE_Y = false; +const bool DISABLE_Z = true; +const bool DISABLE_E = false; + +const bool INVERT_X_DIR = false; +const bool INVERT_Y_DIR = false; +const bool INVERT_Z_DIR = true; +const bool INVERT_E_DIR = false; + +// Sets direction of endstops when homing; 1=MAX, -1=MIN +const int X_HOME_DIR = -1; +const int Y_HOME_DIR = -1; +const int Z_HOME_DIR = -1; + + +//Thermistor settings: + +//Uncomment for 100k thermistor +//#include "ThermistorTable_100k.h" +//#include "BedThermistorTable_100k.h" + +//Uncomment for 200k thermistor +//#include "ThermistorTable_200k.h" +//#include "BedThermistorTable_200k.h" + +//Identical thermistors on heater and bed - use this if you have no heated bed or if the thermistors are the same on both: +#include "ThermistorTable_200k.h" +//#include "ThermistorTable_100k.h" +//#include "ThermistorTable_mendelparts.h" +#define BNUMTEMPS NUMTEMPS +#define bedtemptable temptable + +//Endstop Settings +#define ENDSTOPPULLUPS 1 +const bool ENDSTOPS_INVERTING = false; +const bool min_software_endstops = false; //If true, axis won't move to coordinates less than zero. +const bool max_software_endstops = true; //If true, axis won't move to coordinates greater than the defined lengths below. +const int X_MAX_LENGTH = 220; +const int Y_MAX_LENGTH = 220; +const int Z_MAX_LENGTH = 100; + +#define BAUDRATE 115200 + +//Uncomment the following line to enable debugging. You can better control debugging below the following line +//#define DEBUG +#ifdef DEBUG + //#define DEBUG_PREPARE_MOVE //Enable this to debug prepare_move() function + //#define DEBUG_BRESENHAM //Enable this to debug the Bresenham algorithm + //#define DEBUG_RAMP_ACCELERATION //Enable this to debug all constant acceleration info + //#define DEBUG_MOVE_TIME //Enable this to time each move and print the result + //#define DEBUG_HEAT_MGMT //Enable this to debug heat management. WARNING, this will cause axes to jitter! + //#define DEBUG_DISABLE_CHECK_DURING_TRAVEL //Debug the namesake feature, see above in this file +#endif + +#endif diff --git a/Sprinter/createTemperatureLookup.py b/Sprinter/createTemperatureLookup.py new file mode 100644 index 0000000..e60a490 --- /dev/null +++ b/Sprinter/createTemperatureLookup.py @@ -0,0 +1,127 @@ +#!/usr/bin/python +# +# Creates a C code lookup table for doing ADC to temperature conversion +# on a microcontroller +# based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html +"""Thermistor Value Lookup Table Generator + +Generates lookup to temperature values for use in a microcontroller in C format based on: +http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html + +The main use is for Arduino programs that read data from the circuit board described here: +http://make.rrrf.org/ts-1.0 + +Usage: python createTemperatureLookup.py [options] + +Options: + -h, --help show this help + --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) + --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) + --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta + --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) + --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) + --num-temps=... the number of temperature points to calculate (default: 20) + --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values +""" + +from math import * +import sys +import getopt + +class Thermistor: + "Class to do the thermistor maths" + def __init__(self, r0, t0, beta, r1, r2): + self.r0 = r0 # stated resistance, e.g. 10K + self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C + self.beta = beta # stated beta, e.g. 3500 + self.vadc = 5.0 # ADC reference + self.vcc = 5.0 # supply voltage to potential divider + self.k = r0 * exp(-beta / self.t0) # constant part of calculation + + if r1 > 0: + self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage + self.rs = r1 * r2 / (r1 + r2) # effective bias impedance + else: + self.vs = self.vcc # effective bias voltage + self.rs = r2 # effective bias impedance + + def temp(self,adc): + "Convert ADC reading into a temperature in Celcius" + v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage + r = self.rs * v / (self.vs - v) # resistance of thermistor + return (self.beta / log(r / self.k)) - 273.15 # temperature + + def setting(self, t): + "Convert a temperature into a ADC value" + r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor + v = self.vs * r / (self.rs + r) # the voltage at the potential divider + return round(v / self.vadc * 1024) # the ADC reading + +def main(argv): + + r0 = 10000; + t0 = 25; + beta = 3947; + r1 = 680; + r2 = 1600; + num_temps = int(20); + + try: + opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2="]) + except getopt.GetoptError: + usage() + sys.exit(2) + + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit() + elif opt == "--r0": + r0 = int(arg) + elif opt == "--t0": + t0 = int(arg) + elif opt == "--beta": + beta = int(arg) + elif opt == "--r1": + r1 = int(arg) + elif opt == "--r2": + r2 = int(arg) + + if r1: + max_adc = int(1023 * r1 / (r1 + r2)); + else: + max_adc = 1023 + increment = int(max_adc/(num_temps-1)); + + t = Thermistor(r0, t0, beta, r1, r2) + + adcs = range(1, max_adc, increment); +# adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] + first = 1 + + print "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)" + print "// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)" + print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc) + print "// r0: %s" % (r0) + print "// t0: %s" % (t0) + print "// r1: %s" % (r1) + print "// r2: %s" % (r2) + print "// beta: %s" % (beta) + print "// max adc: %s" % (max_adc) + print "#define NUMTEMPS %s" % (len(adcs)) + print "short temptable[NUMTEMPS][2] = {" + + counter = 0 + for adc in adcs: + counter = counter +1 + if counter == len(adcs): + print " {%s, %s}" % (adc, int(t.temp(adc))) + else: + print " {%s, %s}," % (adc, int(t.temp(adc))) + print "};" + +def usage(): + print __doc__ + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/Sprinter/pins.h b/Sprinter/pins.h new file mode 100644 index 0000000..eee78e8 --- /dev/null +++ b/Sprinter/pins.h @@ -0,0 +1,477 @@ +#ifndef PINS_H +#define PINS_H + +/**************************************************************************************** +* Arduino pin assignment +* +* ATMega168 +* +-\/-+ +* PC6 1| |28 PC5 (AI 5 / D19) +* (D 0) PD0 2| |27 PC4 (AI 4 / D18) +* (D 1) PD1 3| |26 PC3 (AI 3 / D17) +* (D 2) PD2 4| |25 PC2 (AI 2 / D16) +* PWM+ (D 3) PD3 5| |24 PC1 (AI 1 / D15) +* (D 4) PD4 6| |23 PC0 (AI 0 / D14) +* VCC 7| |22 GND +* GND 8| |21 AREF +* PB6 9| |20 AVCC +* PB7 10| |19 PB5 (D 13) +* PWM+ (D 5) PD5 11| |18 PB4 (D 12) +* PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM +* (D 7) PD7 13| |16 PB2 (D 10) PWM +* (D 8) PB0 14| |15 PB1 (D 9) PWM +* +----+ +****************************************************************************************/ +#if MOTHERBOARD == 0 +#ifndef __AVR_ATmega168__ +#error Oops! Make sure you have 'Arduino Diecimila' selected from the boards menu. +#endif + +#define X_STEP_PIN 2 +#define X_DIR_PIN 3 +#define X_ENABLE_PIN -1 +#define X_MIN_PIN 4 +#define X_MAX_PIN 9 + +#define Y_STEP_PIN 10 +#define Y_DIR_PIN 7 +#define Y_ENABLE_PIN -1 +#define Y_MIN_PIN 8 +#define Y_MAX_PIN 13 + +#define Z_STEP_PIN 19 +#define Z_DIR_PIN 18 +#define Z_ENABLE_PIN 5 +#define Z_MIN_PIN 17 +#define Z_MAX_PIN 16 + +#define E_STEP_PIN 11 +#define E_DIR_PIN 12 +#define E_ENABLE_PIN -1 + +#define SDPOWER -1 +#define SDSS -1 +#define LED_PIN -1 +#define FAN_PIN -1 +#define PS_ON_PIN 15 +#define KILL_PIN -1 + +#define HEATER_0_PIN 6 +#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! + + + + + + +/**************************************************************************************** +* Sanguino/RepRap Motherboard with direct-drive extruders +* +* ATMega644P +* +* +---\/---+ +* (D 0) PB0 1| |40 PA0 (AI 0 / D31) +* (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 +* INT0 RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS +* INT1 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 +* +--------+ +* +****************************************************************************************/ +#elif MOTHERBOARD == 1 +#ifndef __AVR_ATmega644P__ +#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. +#endif + +#define X_STEP_PIN 15 +#define X_DIR_PIN 18 +#define X_ENABLE_PIN 19 +#define X_MIN_PIN 20 +#define X_MAX_PIN 21 + +#define Y_STEP_PIN 23 +#define Y_DIR_PIN 22 +#define Y_ENABLE_PIN 19 +#define Y_MIN_PIN 25 +#define Y_MAX_PIN 26 + +#define Z_STEP_PIN 29 +#define Z_DIR_PIN 30 +#define Z_ENABLE_PIN 31 +#define Z_MIN_PIN 2 +#define Z_MAX_PIN 1 + +#define E_STEP_PIN 12 +#define E_DIR_PIN 16 +#define E_ENABLE_PIN 3 + +#define SDPOWER -1 +#define SDSS -1 +#define LED_PIN 0 +#define FAN_PIN -1 +#define PS_ON_PIN -1 +#define KILL_PIN -1 + +#define HEATER_0_PIN 14 +#define TEMP_0_PIN 4 //D27 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! + +/* Unused (1) (2) (3) 4 5 6 7 8 9 10 11 12 13 (14) (15) (16) 17 (18) (19) (20) (21) (22) (23) 24 (25) (26) (27) 28 (29) (30) (31) */ + + + + + + +/**************************************************************************************** +* RepRap Motherboard ****---NOOOOOO RS485/EXTRUDER CONTROLLER!!!!!!!!!!!!!!!!!---******* +* +****************************************************************************************/ +#elif MOTHERBOARD == 2 +#ifndef __AVR_ATmega644P__ +#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. +#endif + +#define X_STEP_PIN 15 +#define X_DIR_PIN 18 +#define X_ENABLE_PIN 19 +#define X_MIN_PIN 20 +#define X_MAX_PIN 21 + +#define Y_STEP_PIN 23 +#define Y_DIR_PIN 22 +#define Y_ENABLE_PIN 24 +#define Y_MIN_PIN 25 +#define Y_MAX_PIN 26 + +#define Z_STEP_PINN 27 +#define Z_DIR_PINN 28 +#define Z_ENABLE_PIN 29 +#define Z_MIN_PIN 30 +#define Z_MAX_PIN 31 + +#define E_STEP_PIN 17 +#define E_DIR_PIN 16 +#define E_ENABLE_PIN -1 + +#define SDPOWER -1 +#define SDSS 4 +#define LED_PIN 0 + +#define SD_CARD_WRITE 2 +#define SD_CARD_DETECT 3 +#define SD_CARD_SELECT 4 + +//our RS485 pins +#define TX_ENABLE_PIN 12 +#define RX_ENABLE_PIN 13 + +//pin for controlling the PSU. +#define PS_ON_PIN 14 + +#define FAN_PIN -1 +#define KILL_PIN -1 + +#define HEATER_0_PIN -1 +#define TEMP_0_PIN -1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! + + + + + + +/**************************************************************************************** +* Arduino Mega pin assignment +* +****************************************************************************************/ +#elif MOTHERBOARD == 3 +//////////////////FIX THIS////////////// +#ifndef __AVR_ATmega1280__ + #ifndef __AVR_ATmega2560__ + #error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu. + #endif +#endif + +// uncomment one of the following lines for RAMPS v1.3 or v1.0, comment both for v1.2 or 1.1 +// #define RAMPS_V_1_3 +// #define RAMPS_V_1_0 + + +#ifdef RAMPS_V_1_3 + +#define X_STEP_PIN 54 +#define X_DIR_PIN 55 +#define X_ENABLE_PIN 38 +#define X_MIN_PIN 3 +#define X_MAX_PIN -1 //2 //Max endstops default to disabled "-1", set to commented value to enable. + +#define Y_STEP_PIN 60 +#define Y_DIR_PIN 61 +#define Y_ENABLE_PIN 56 +#define Y_MIN_PIN 14 +#define Y_MAX_PIN -1 //15 + +#define Z_STEP_PIN 46 +#define Z_DIR_PIN 48 +#define Z_ENABLE_PIN 62 +#define Z_MIN_PIN 18 +#define Z_MAX_PIN -1 //19 + +#define E_STEP_PIN 26 +#define E_DIR_PIN 28 +#define E_ENABLE_PIN 24 + +#define SDPOWER -1 +#define SDSS 53 +#define LED_PIN 13 +#define FAN_PIN 9 +#define PS_ON_PIN 12 +#define KILL_PIN -1 + +#define HEATER_0_PIN 10 +#define HEATER_1_PIN 8 +#define TEMP_0_PIN 13 // ANALOG NUMBERING +#define TEMP_1_PIN 14 // ANALOG NUMBERING + + +#else // RAMPS_V_1_1 or RAMPS_V_1_2 as default + +#define X_STEP_PIN 26 +#define X_DIR_PIN 28 +#define X_ENABLE_PIN 24 +#define X_MIN_PIN 3 +#define X_MAX_PIN -1 //2 + +#define Y_STEP_PIN 38 +#define Y_DIR_PIN 40 +#define Y_ENABLE_PIN 36 +#define Y_MIN_PIN 16 +#define Y_MAX_PIN -1 //17 + +#define Z_STEP_PIN 44 +#define Z_DIR_PIN 46 +#define Z_ENABLE_PIN 42 +#define Z_MIN_PIN 18 +#define Z_MAX_PIN -1 //19 + +#define E_STEP_PIN 32 +#define E_DIR_PIN 34 +#define E_ENABLE_PIN 30 + +#define SDPOWER 48 +#define SDSS 53 +#define LED_PIN 13 +#define PS_ON_PIN -1 +#define KILL_PIN -1 + + + +#ifdef RAMPS_V_1_0 // RAMPS_V_1_0 + #define HEATER_0_PIN 12 // RAMPS 1.0 + #define HEATER_1_PIN -1 // RAMPS 1.0 + #define FAN_PIN 11 // RAMPS 1.0 + +#else // RAMPS_V_1_1 or RAMPS_V_1_2 + #define HEATER_0_PIN 10 // RAMPS 1.1 + #define HEATER_1_PIN 8 // RAMPS 1.1 + #define FAN_PIN 9 // RAMPS 1.1 +#endif + +#define TEMP_0_PIN 2 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! +#define TEMP_1_PIN 1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! +#endif + +// SPI for Max6675 Thermocouple + +#ifndef SDSUPPORT +// these pins are defined in the SD library if building with SD support #define SCK_PIN 52 + #define MISO_PIN 50 + #define MOSI_PIN 51 + #define MAX6675_SS 53 +#else + #define MAX6675_SS 49 +#endif + + + +/**************************************************************************************** +* Duemilanove w/ ATMega328P pin assignment +* +****************************************************************************************/ +#elif MOTHERBOARD == 4 +#ifndef __AVR_ATmega328P__ +#error Oops! Make sure you have 'Arduino Duemilanove w/ ATMega328' selected from the 'Tools -> Boards' menu. +#endif + +#define X_STEP_PIN 19 +#define X_DIR_PIN 18 +#define X_ENABLE_PIN -1 +#define X_MIN_PIN 17 +#define X_MAX_PIN -1 + +#define Y_STEP_PIN 10 +#define Y_DIR_PIN 7 +#define Y_ENABLE_PIN -1 +#define Y_MIN_PIN 8 +#define Y_MAX_PIN -1 + +#define Z_STEP_PIN 13 +#define Z_DIR_PIN 3 +#define Z_ENABLE_PIN 2 +#define Z_MIN_PIN 4 +#define Z_MAX_PIN -1 + +#define E_STEP_PIN 11 +#define E_DIR_PIN 12 +#define E_ENABLE_PIN -1 + +#define SDPOWER -1 +#define SDSS -1 +#define LED_PIN -1 +#define FAN_PIN 5 +#define PS_ON_PIN -1 +#define KILL_PIN -1 + +#define HEATER_0_PIN 6 +#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! + + + + +/**************************************************************************************** +* Gen6 pin assignment +* +****************************************************************************************/ +#elif MOTHERBOARD == 5 + +#ifndef __AVR_ATmega644P__ + #error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. +#endif + +//x axis pins + #define X_STEP_PIN 15 + #define X_DIR_PIN 18 + #define X_ENABLE_PIN 19 + #define X_MIN_PIN 20 + #define X_MAX_PIN -1 + + //y axis pins + #define Y_STEP_PIN 23 + #define Y_DIR_PIN 22 + #define Y_ENABLE_PIN 24 + #define Y_MIN_PIN 25 + #define Y_MAX_PIN -1 + + //z axis pins + #define Z_STEP_PIN 27 + #define Z_DIR_PIN 28 + #define Z_ENABLE_PIN 29 + #define Z_MIN_PIN 30 + #define Z_MAX_PIN -1 + + //extruder pins + #define E_STEP_PIN 4 //Edited @ EJE Electronics 20100715 + #define E_DIR_PIN 2 //Edited @ EJE Electronics 20100715 + #define E_ENABLE_PIN 3 //Added @ EJE Electronics 20100715 + #define TEMP_0_PIN 5 //changed @ rkoeppl 20110410 + #define HEATER_0_PIN 14 //changed @ rkoeppl 20110410 + #define HEATER_1_PIN -1 //changed @ rkoeppl 20110410 + + + #define SDPOWER -1 + #define SDSS -1 + #define LED_PIN -1 //changed @ rkoeppl 20110410 + #define TEMP_1_PIN -1 //changed @ rkoeppl 20110410 + #define FAN_PIN -1 //changed @ rkoeppl 20110410 + #define PS_ON_PIN -1 //changed @ rkoeppl 20110410 + //our pin for debugging. + + #define DEBUG_PIN 0 + + //our RS485 pins + #define TX_ENABLE_PIN 12 + #define RX_ENABLE_PIN 13 + + +/**************************************************************************************** +* Sanguinololu pin assignment +* +****************************************************************************************/ +#elif MOTHERBOARD == 6 +#ifndef __AVR_ATmega644P__ +#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. +#endif + +// uncomment the following line for Sanguinololu v1.2, comment for 1.1 or earlier. +// #define SANGUINOLOLU_V_1_2 + + +#define X_STEP_PIN 15 +#define X_DIR_PIN 21 +#define X_ENABLE_PIN -1 +#define X_MIN_PIN 18 +#define X_MAX_PIN -2 //2 + +#define Y_STEP_PIN 22 +#define Y_DIR_PIN 23 +#define Y_ENABLE_PIN -1 +#define Y_MIN_PIN 19 +#define Y_MAX_PIN -1 //17 + +#define Z_STEP_PIN 3 +#define Z_DIR_PIN 2 +// zenable defined by platform below +#define Z_MIN_PIN 20 +#define Z_MAX_PIN -1 //19 + +#define E_STEP_PIN 1 +#define E_DIR_PIN 0 +#define E_ENABLE_PIN -1 + +#define LED_PIN -1 + +#define FAN_PIN -1 // THIS LINE FOR V1.0 + +#define PS_ON_PIN -1 +#define KILL_PIN -1 + +#define HEATER_0_PIN 13 // THIS LINE FOR V1.0+ (extruder) + +#ifdef SANGUINOLOLU_V_1_2 + +#define HEATER_1_PIN 12 // (bed) +#define Z_ENABLE_PIN 26 + +#else + +#define HEATER_1_PIN 14 // (bed) +#define Z_ENABLE_PIN -1 + +#endif + +#define TEMP_0_PIN 7 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 33 extruder) +#define TEMP_1_PIN 6 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed) +#define SDPOWER -1 +#define SDSS 31 + +#else + +#error Unknown MOTHERBOARD value in configuration.h + +#endif + +#endif diff --git a/Tonokip_Firmware/BedThermistorTable_100k.h b/Tonokip_Firmware/BedThermistorTable_100k.h deleted file mode 100644 index 84bc607..0000000 --- a/Tonokip_Firmware/BedThermistorTable_100k.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef THERMISTORTABLE_H_ -#define THERMISTORTABLE_H_ - -// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) -// See this page: -// http://dev.www.reprap.org/bin/view/Main/Thermistor -// for details of what goes in this table. -// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) -// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 -// r0: 100000 -// t0: 25 -// r1: 0 -// r2: 4700 -// beta: 4066 -// max adc: 1023 - -#define BNUMTEMPS 61 -const short bedtemptable[BNUMTEMPS][2] = { -{ 23 , 300 }, -{ 25 , 295 }, -{ 27 , 290 }, -{ 28 , 285 }, -{ 31 , 280 }, -{ 33 , 275 }, -{ 35 , 270 }, -{ 38 , 265 }, -{ 41 , 260 }, -{ 44 , 255 }, -{ 48 , 250 }, -{ 52 , 245 }, -{ 56 , 240 }, -{ 61 , 235 }, -{ 66 , 230 }, -{ 71 , 225 }, -{ 78 , 220 }, -{ 84 , 215 }, -{ 92 , 210 }, -{ 100 , 205 }, -{ 109 , 200 }, -{ 120 , 195 }, -{ 131 , 190 }, -{ 143 , 185 }, -{ 156 , 180 }, -{ 171 , 175 }, -{ 187 , 170 }, -{ 205 , 165 }, -{ 224 , 160 }, -{ 245 , 155 }, -{ 268 , 150 }, -{ 293 , 145 }, -{ 320 , 140 }, -{ 348 , 135 }, -{ 379 , 130 }, -{ 411 , 125 }, -{ 445 , 120 }, -{ 480 , 115 }, -{ 516 , 110 }, -{ 553 , 105 }, -{ 591 , 100 }, -{ 628 , 95 }, -{ 665 , 90 }, -{ 702 , 85 }, -{ 737 , 80 }, -{ 770 , 75 }, -{ 801 , 70 }, -{ 830 , 65 }, -{ 857 , 60 }, -{ 881 , 55 }, -{ 903 , 50 }, -{ 922 , 45 }, -{ 939 , 40 }, -{ 954 , 35 }, -{ 966 , 30 }, -{ 977 , 25 }, -{ 985 , 20 }, -{ 993 , 15 }, -{ 999 , 10 }, -{ 1004 , 5 }, -{ 1008 , 0 }, - -}; - - -#endif - diff --git a/Tonokip_Firmware/BedThermistorTable_200k.h b/Tonokip_Firmware/BedThermistorTable_200k.h deleted file mode 100644 index 3d96aa3..0000000 --- a/Tonokip_Firmware/BedThermistorTable_200k.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef THERMISTORTABLE_H_ -#define THERMISTORTABLE_H_ - -// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) -// See this page: -// http://dev.www.reprap.org/bin/view/Main/Thermistor -// for details of what goes in this table. -// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) -// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 -// r0: 100000 -// t0: 25 -// r1: 0 -// r2: 4700 -// beta: 4066 -// max adc: 1023 - -#define BNUMTEMPS 20 -const short bedtemptable[BNUMTEMPS][2] = { - {1, 848}, - {54, 275}, - {107, 228}, - {160, 202}, - {213, 185}, - {266, 171}, - {319, 160}, - {372, 150}, - {425, 141}, - {478, 133}, - {531, 125}, - {584, 118}, - {637, 110}, - {690, 103}, - {743, 95}, - {796, 86}, - {849, 77}, - {902, 65}, - {955, 49}, - {1008, 17} -}; - - -#endif diff --git a/Tonokip_Firmware/FatStructs.h b/Tonokip_Firmware/FatStructs.h deleted file mode 100644 index f5bdaa5..0000000 --- a/Tonokip_Firmware/FatStructs.h +++ /dev/null @@ -1,418 +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 - * . - */ -#ifndef FatStructs_h -#define FatStructs_h -/** - * \file - * FAT file structures - */ -/* - * mostly from Microsoft document fatgen103.doc - * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx - */ -//------------------------------------------------------------------------------ -/** Value for byte 510 of boot block or MBR */ -uint8_t const BOOTSIG0 = 0X55; -/** Value for byte 511 of boot block or MBR */ -uint8_t const BOOTSIG1 = 0XAA; -//------------------------------------------------------------------------------ -/** - * \struct partitionTable - * \brief MBR partition table entry - * - * A partition table entry for a MBR formatted storage device. - * The MBR partition table has four entries. - */ -struct partitionTable { - /** - * Boot Indicator . Indicates whether the volume is the active - * partition. Legal values include: 0X00. Do not use for booting. - * 0X80 Active partition. - */ - uint8_t boot; - /** - * Head part of Cylinder-head-sector address of the first block in - * the partition. Legal values are 0-255. Only used in old PC BIOS. - */ - uint8_t beginHead; - /** - * Sector part of Cylinder-head-sector address of the first block in - * the partition. Legal values are 1-63. Only used in old PC BIOS. - */ - unsigned beginSector : 6; - /** High bits cylinder for first block in partition. */ - unsigned beginCylinderHigh : 2; - /** - * Combine beginCylinderLow with beginCylinderHigh. Legal values - * are 0-1023. Only used in old PC BIOS. - */ - uint8_t beginCylinderLow; - /** - * Partition type. See defines that begin with PART_TYPE_ for - * some Microsoft partition types. - */ - uint8_t type; - /** - * head part of cylinder-head-sector address of the last sector in the - * partition. Legal values are 0-255. Only used in old PC BIOS. - */ - uint8_t endHead; - /** - * Sector part of cylinder-head-sector address of the last sector in - * the partition. Legal values are 1-63. Only used in old PC BIOS. - */ - unsigned endSector : 6; - /** High bits of end cylinder */ - unsigned endCylinderHigh : 2; - /** - * Combine endCylinderLow with endCylinderHigh. Legal values - * are 0-1023. Only used in old PC BIOS. - */ - uint8_t endCylinderLow; - /** Logical block address of the first block in the partition. */ - uint32_t firstSector; - /** Length of the partition, in blocks. */ - uint32_t totalSectors; -}; -/** Type name for partitionTable */ -typedef struct partitionTable part_t; -//------------------------------------------------------------------------------ -/** - * \struct masterBootRecord - * - * \brief Master Boot Record - * - * The first block of a storage device that is formatted with a MBR. - */ -struct masterBootRecord { - /** Code Area for master boot program. */ - uint8_t codeArea[440]; - /** Optional WindowsNT disk signature. May contain more boot code. */ - uint32_t diskSignature; - /** Usually zero but may be more boot code. */ - uint16_t usuallyZero; - /** Partition tables. */ - part_t part[4]; - /** First MBR signature byte. Must be 0X55 */ - uint8_t mbrSig0; - /** Second MBR signature byte. Must be 0XAA */ - uint8_t mbrSig1; -}; -/** Type name for masterBootRecord */ -typedef struct masterBootRecord mbr_t; -//------------------------------------------------------------------------------ -/** - * \struct biosParmBlock - * - * \brief BIOS parameter block - * - * The BIOS parameter block describes the physical layout of a FAT volume. - */ -struct biosParmBlock { - /** - * Count of bytes per sector. This value may take on only the - * following values: 512, 1024, 2048 or 4096 - */ - 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. - */ - uint8_t sectorsPerCluster; - /** - * Number of sectors before the first FAT. - * This value must not be zero. - */ - 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. - */ - 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. - */ - 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 - * FAT12 and FAT16 volumes, this field contains the sector count, and - * totalSectors32 is 0 if the total sector count fits - * (is less than 0x10000). - */ - 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 (non-removable) media. For removable media, 0xF0 is - * frequently used. Legal values are 0xF0 or 0xF8-0xFF. - */ - uint8_t mediaType; - /** - * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. - * 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 sectorsPerTrtack; - /** 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; - /** - * 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. - */ - uint32_t totalSectors32; - /** - * Count of sectors occupied by one FAT on FAT32 volumes. - */ - uint32_t sectorsPerFat32; - /** - * This field is only defined for FAT32 media and does not exist on - * FAT12 and FAT16 media. - * Bits 0-3 -- Zero-based number of active FAT. - * 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. - * Bits 8-15 -- Reserved. - */ - uint16_t fat32Flags; - /** - * FAT32 version. High byte is major revision number. - * Low byte is minor revision number. Only 0.0 define. - */ - uint16_t fat32Version; - /** - * Cluster number of the first cluster of the root directory for FAT32. - * This usually 2 but not required to be 2. - */ - uint32_t fat32RootCluster; - /** - * Sector number of FSINFO structure in the reserved area of the - * FAT32 volume. Usually 1. - */ - uint16_t fat32FSInfo; - /** - * If non-zero, 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. - */ - uint16_t fat32BackBootBlock; - /** - * Reserved for future expansion. Code that formats FAT32 volumes - * 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 */ - 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 */ - uint32_t volumeSerialNumber; - /** should match volume label in root dir */ - char volumeLabel[11]; - /** informational only - don't depend on it */ - char fileSystemType[8]; - /** X86 boot code */ - uint8_t bootCode[420]; - /** must be 0X55 */ - uint8_t bootSectorSig0; - /** must be 0XAA */ - uint8_t bootSectorSig1; -}; -//------------------------------------------------------------------------------ -// End Of Chain values for FAT entries -/** FAT16 end of chain value used by Microsoft. */ -uint16_t const FAT16EOC = 0XFFFF; -/** Minimum value for FAT16 EOC. Use to test for EOC. */ -uint16_t const FAT16EOC_MIN = 0XFFF8; -/** FAT32 end of chain value used by Microsoft. */ -uint32_t const FAT32EOC = 0X0FFFFFFF; -/** Minimum value for FAT32 EOC. Use to test for EOC. */ -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 - * \brief FAT short directory entry - * - * Short means short 8.3 name, not the entry size. - * - * Date Format. A FAT directory entry date stamp is a 16-bit field that is - * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the - * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the - * 16-bit word): - * - * Bits 9-15: Count of years from 1980, valid value range 0-127 - * inclusive (1980-2107). - * - * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. - * - * Bits 0-4: Day of month, valid value range 1-31 inclusive. - * - * Time Format. A FAT directory entry time stamp is a 16-bit field that has - * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the - * 16-bit word, bit 15 is the MSB of the 16-bit word). - * - * Bits 11-15: Hours, valid value range 0-23 inclusive. - * - * Bits 5-10: Minutes, valid value range 0-59 inclusive. - * - * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). - * - * The valid time range is from Midnight 00:00:00 to 23:59:58. - */ -struct directoryEntry { - /** - * 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. - */ - uint8_t name[11]; - /** Entry attributes. - * - * The upper two bits of the attribute byte are reserved and should - * always be set to 0 when a file is created and never modified or - * looked at after that. See defines that begin with DIR_ATT_. - */ - uint8_t attributes; - /** - * Reserved for use by Windows NT. Set value to 0 when a file is - * created and never modify or look at it after that. - */ - uint8_t reservedNT; - /** - * The granularity of the seconds part of creationTime is 2 seconds - * so this field is a count of tenths of a second and its valid - * value range is 0-199 inclusive. (WHG note - seems to be hundredths) - */ - uint8_t creationTimeTenths; - /** Time file was created. */ - uint16_t creationTime; - /** Date file was created. */ - uint16_t creationDate; - /** - * Last access date. Note that there is no last access time, only - * a date. This is the date of last read or write. In the case of - * a write, this should be set to the same date as lastWriteDate. - */ - uint16_t lastAccessDate; - /** - * High word of this entry's first cluster number (always 0 for a - * FAT12 or FAT16 volume). - */ - uint16_t firstClusterHigh; - /** Time of last write. File creation is considered a write. */ - uint16_t lastWriteTime; - /** Date of last write. File creation is considered a write. */ - uint16_t lastWriteDate; - /** Low word of this entry's first cluster number. */ - uint16_t firstClusterLow; - /** 32-bit unsigned holding this file's size in bytes. */ - uint32_t fileSize; -}; -//------------------------------------------------------------------------------ -// Definitions for directory entries -// -/** Type name for directoryEntry */ -typedef struct directoryEntry dir_t; -/** escape for name[0] = 0XE5 */ -uint8_t const DIR_NAME_0XE5 = 0X05; -/** name[0] value for entry that is free after being "deleted" */ -uint8_t const DIR_NAME_DELETED = 0XE5; -/** name[0] value for entry that is free and no allocated entries follow */ -uint8_t const DIR_NAME_FREE = 0X00; -/** file is read-only */ -uint8_t const DIR_ATT_READ_ONLY = 0X01; -/** File should hidden in directory listings */ -uint8_t const DIR_ATT_HIDDEN = 0X02; -/** Entry is for a system file */ -uint8_t const DIR_ATT_SYSTEM = 0X04; -/** Directory entry contains the volume label */ -uint8_t const DIR_ATT_VOLUME_ID = 0X08; -/** Entry is for a directory */ -uint8_t const DIR_ATT_DIRECTORY = 0X10; -/** Old DOS archive bit for backup support */ -uint8_t const DIR_ATT_ARCHIVE = 0X20; -/** Test value for long name entry. Test is - (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */ -uint8_t const DIR_ATT_LONG_NAME = 0X0F; -/** Test mask for long name entry */ -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 */ -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 */ -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 */ -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 */ -static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { - return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; -} -#endif // FatStructs_h diff --git a/Tonokip_Firmware/Makefile b/Tonokip_Firmware/Makefile deleted file mode 100644 index 618b384..0000000 --- a/Tonokip_Firmware/Makefile +++ /dev/null @@ -1,247 +0,0 @@ -# Sprinter Arduino Project Makefile -# -# Makefile Based on: -# Arduino 0011 Makefile -# Arduino adaptation by mellis, eighthave, oli.keller -# -# This has been tested with Arduino 0022. -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment (or Java). -# -# Detailed instructions for using the makefile: -# -# 1. Modify the line containg "INSTALL_DIR" to point to the directory that -# contains the Arduino installation (for example, under Mac OS X, this -# might be /Applications/arduino-0012). -# -# 2. Modify the line containing "PORT" to refer to the filename -# representing the USB or serial connection to your Arduino board -# (e.g. PORT = /dev/tty.USB0). If the exact name of this file -# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.usb*). -# -# 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. -# -# 4. Type "make" and press enter to compile/verify your program. -# -# 5. Type "make upload", reset your Arduino board, and press enter to -# upload your program to the Arduino board. -# -# $Id$ - -TARGET = $(notdir $(CURDIR)) -INSTALL_DIR = /home/chris/arduino-0022 -UPLOAD_RATE = 38400 -AVRDUDE_PROGRAMMER = stk500v1 -PORT = /dev/ttyUSB0 -MCU = atmega2560 -#For "old" Arduino Mega -#MCU = atmega1280 -#For Sanguinololu -#MCU = atmega644p -F_CPU = 16000000 - - -############################################################################ -# Below here nothing should be changed... - -ARDUINO = $(INSTALL_DIR)/hardware/arduino/cores/arduino -AVR_TOOLS_PATH = /usr/bin -SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \ -$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \ -$(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \ -$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c -CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp \ -$(ARDUINO)/Print.cpp ./SdFile.cpp ./SdVolume.cpp ./Sd2Card.cpp -FORMAT = ihex - - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU) -CXXDEFS = -DF_CPU=$(F_CPU) - -# Place -I options here -CINCS = -I$(ARDUINO) -CXXINCS = -I$(ARDUINO) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) - -CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = -lm - - -# Programming support using avrdude. Settings and variables. -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) - -# 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 -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: applet_files build sizeafter - -build: elf hex - -applet_files: $(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.cxx >> applet/$(TARGET).cpp - -elf: applet/$(TARGET).elf -hex: applet/$(TARGET).hex -eep: applet/$(TARGET).eep -lss: applet/$(TARGET).lss -sym: applet/$(TARGET).sym - -# Program the device. -upload: applet/$(TARGET).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) - - - # Display size of file. -HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex -ELFSIZE = $(SIZE) applet/$(TARGET).elf -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 - - -# 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 - - -coff: applet/$(TARGET).elf - $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf $(TARGET).cof - - -extcoff: $(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - # Link: create ELF output file from library. -applet/$(TARGET).elf: $(TARGET).pde applet/core.a - $(CC) $(ALL_CFLAGS) -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 $@ - - - -# 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) - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter diff --git a/Tonokip_Firmware/Sd2Card.cpp b/Tonokip_Firmware/Sd2Card.cpp deleted file mode 100644 index 8222cfd..0000000 --- a/Tonokip_Firmware/Sd2Card.cpp +++ /dev/null @@ -1,643 +0,0 @@ -/* 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 - * . - */ -#include -#include "Sd2Card.h" -//------------------------------------------------------------------------------ -#ifndef SOFTWARE_SPI -// functions for hardware SPI -/** Send a byte to the card */ -static void spiSend(uint8_t b) { - SPDR = b; - while (!(SPSR & (1 << SPIF))); -} -/** Receive a byte from the card */ -static uint8_t spiRec(void) { - spiSend(0XFF); - return SPDR; -} -#else // SOFTWARE_SPI -//------------------------------------------------------------------------------ -/** nop to tune soft SPI timing */ -#define nop asm volatile ("nop\n\t") -//------------------------------------------------------------------------------ -/** Soft SPI receive */ -uint8_t spiRec(void) { - uint8_t data = 0; - // no interrupts during byte receive - about 8 us - cli(); - // output pin high - like sending 0XFF - fastDigitalWrite(SPI_MOSI_PIN, HIGH); - - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, HIGH); - - // adjust so SCK is nice - nop; - nop; - - data <<= 1; - - if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - } - // enable interrupts - sei(); - return data; -} -//------------------------------------------------------------------------------ -/** Soft SPI send */ -void spiSend(uint8_t data) { - // no interrupts during byte send - about 8 us - cli(); - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, LOW); - - fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); - - data <<= 1; - - fastDigitalWrite(SPI_SCK_PIN, HIGH); - } - // hold SCK high for a few ns - nop; - nop; - nop; - nop; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - // enable interrupts - sei(); -} -#endif // SOFTWARE_SPI -//------------------------------------------------------------------------------ -// send command and return error code. Return zero for OK -uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { - // end read if in partialBlockRead mode - readEnd(); - - // select card - chipSelectLow(); - - // wait up to 300 ms if busy - waitNotBusy(300); - - // send command - spiSend(cmd | 0x40); - - // send argument - for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); - - // send CRC - uint8_t crc = 0XFF; - if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 - if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA - spiSend(crc); - - // wait for response - for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); - return status_; -} -//------------------------------------------------------------------------------ -/** - * Determine the size of an SD flash memory card. - * - * \return The number of 512 byte data blocks in the card - * or zero if an error occurs. - */ -uint32_t Sd2Card::cardSize(void) { - csd_t csd; - if (!readCSD(&csd)) return 0; - if (csd.v1.csd_ver == 0) { - uint8_t read_bl_len = csd.v1.read_bl_len; - uint16_t c_size = (csd.v1.c_size_high << 10) - | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; - uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) - | csd.v1.c_size_mult_low; - return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); - } else if (csd.v2.csd_ver == 1) { - uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) - | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; - return (c_size + 1) << 10; - } else { - error(SD_CARD_ERROR_BAD_CSD); - return 0; - } -} -//------------------------------------------------------------------------------ -void Sd2Card::chipSelectHigh(void) { - digitalWrite(chipSelectPin_, HIGH); -} -//------------------------------------------------------------------------------ -void Sd2Card::chipSelectLow(void) { - digitalWrite(chipSelectPin_, LOW); -} -//------------------------------------------------------------------------------ -/** Erase a range of blocks. - * - * \param[in] firstBlock The address of the first block in the range. - * \param[in] lastBlock The address of the last block in the range. - * - * \note This function requests the SD card to do a flash erase for a - * range of blocks. The data on the card after an erase operation is - * either 0 or 1, depends on the card vendor. The card must support - * single block erase. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { - if (!eraseSingleBlockEnable()) { - error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); - goto fail; - } - if (type_ != SD_CARD_TYPE_SDHC) { - firstBlock <<= 9; - lastBlock <<= 9; - } - if (cardCommand(CMD32, firstBlock) - || cardCommand(CMD33, lastBlock) - || cardCommand(CMD38, 0)) { - error(SD_CARD_ERROR_ERASE); - goto fail; - } - if (!waitNotBusy(SD_ERASE_TIMEOUT)) { - error(SD_CARD_ERROR_ERASE_TIMEOUT); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Determine if card supports single block erase. - * - * \return The value one, true, is returned if single block erase is supported. - * The value zero, false, is returned if single block erase is not supported. - */ -uint8_t Sd2Card::eraseSingleBlockEnable(void) { - csd_t csd; - return readCSD(&csd) ? csd.v1.erase_blk_en : 0; -} -//------------------------------------------------------------------------------ -/** - * Initialize an SD flash memory card. - * - * \param[in] sckRateID SPI clock rate selector. See setSckRate(). - * \param[in] chipSelectPin SD chip select pin number. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. The reason for failure - * can be determined by calling errorCode() and errorData(). - */ -uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { - errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; - chipSelectPin_ = chipSelectPin; - // 16-bit init start time allows over a minute - uint16_t t0 = (uint16_t)millis(); - uint32_t arg; - - // set pin modes - pinMode(chipSelectPin_, OUTPUT); - chipSelectHigh(); - pinMode(SPI_MISO_PIN, INPUT); - pinMode(SPI_MOSI_PIN, OUTPUT); - pinMode(SPI_SCK_PIN, OUTPUT); - -#ifndef SOFTWARE_SPI - // SS must be in output mode even it is not chip select - pinMode(SS_PIN, OUTPUT); - // Enable SPI, Master, clock rate f_osc/128 - SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); - // clear double speed - SPSR &= ~(1 << SPI2X); -#endif // SOFTWARE_SPI - - // must supply min of 74 clock cycles with CS high. - for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); - - chipSelectLow(); - - // command to go idle in SPI mode - while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_CMD0); - goto fail; - } - } - // check SD version - if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { - type(SD_CARD_TYPE_SD1); - } else { - // only need last byte of r7 response - for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); - if (status_ != 0XAA) { - error(SD_CARD_ERROR_CMD8); - goto fail; - } - type(SD_CARD_TYPE_SD2); - } - // initialize card and send host supports SDHC if SD2 - arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; - - while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { - // check for timeout - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_ACMD41); - goto fail; - } - } - // if SD2 read OCR register to check for SDHC card - if (type() == SD_CARD_TYPE_SD2) { - if (cardCommand(CMD58, 0)) { - error(SD_CARD_ERROR_CMD58); - goto fail; - } - if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); - // discard rest of ocr - contains allowed voltage range - for (uint8_t i = 0; i < 3; i++) spiRec(); - } - chipSelectHigh(); - -#ifndef SOFTWARE_SPI - return setSckRate(sckRateID); -#else // SOFTWARE_SPI - return true; -#endif // SOFTWARE_SPI - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Enable or disable partial block reads. - * - * Enabling partial block reads improves performance by allowing a block - * to be read over the SPI bus as several sub-blocks. Errors may occur - * if the time between reads is too long since the SD card may timeout. - * The SPI SS line will be held low until the entire block is read or - * readEnd() is called. - * - * Use this for applications like the Adafruit Wave Shield. - * - * \param[in] value The value TRUE (non-zero) or FALSE (zero).) - */ -void Sd2Card::partialBlockRead(uint8_t value) { - readEnd(); - partialBlockRead_ = value; -} -//------------------------------------------------------------------------------ -/** - * Read a 512 byte block from an SD card device. - * - * \param[in] block Logical block to be read. - * \param[out] dst Pointer to the location that will receive the data. - - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) { - return readData(block, 0, 512, dst); -} -//------------------------------------------------------------------------------ -/** - * Read part of a 512 byte block from an SD card. - * - * \param[in] block Logical block to be read. - * \param[in] offset Number of bytes to skip at start of block - * \param[out] dst Pointer to the location that will receive the data. - * \param[in] count Number of bytes to read - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::readData(uint32_t block, - uint16_t offset, uint16_t count, uint8_t* dst) { - uint16_t n; - if (count == 0) return true; - if ((count + offset) > 512) { - goto fail; - } - if (!inBlock_ || block != block_ || offset < offset_) { - block_ = block; - // use address if not SDHC card - if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; - if (cardCommand(CMD17, block)) { - error(SD_CARD_ERROR_CMD17); - goto fail; - } - if (!waitStartBlock()) { - goto fail; - } - offset_ = 0; - inBlock_ = 1; - } - -#ifdef OPTIMIZE_HARDWARE_SPI - // start first spi transfer - SPDR = 0XFF; - - // skip data before offset - for (;offset_ < offset; offset_++) { - while (!(SPSR & (1 << SPIF))); - SPDR = 0XFF; - } - // transfer data - n = count - 1; - for (uint16_t i = 0; i < n; i++) { - while (!(SPSR & (1 << SPIF))); - dst[i] = SPDR; - SPDR = 0XFF; - } - // wait for last byte - while (!(SPSR & (1 << SPIF))); - dst[n] = SPDR; - -#else // OPTIMIZE_HARDWARE_SPI - - // skip data before offset - for (;offset_ < offset; offset_++) { - spiRec(); - } - // transfer data - for (uint16_t i = 0; i < count; i++) { - dst[i] = spiRec(); - } -#endif // OPTIMIZE_HARDWARE_SPI - - offset_ += count; - if (!partialBlockRead_ || offset_ >= 512) { - // read rest of data, checksum and set chip select high - readEnd(); - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Skip remaining data in a block when in partial block read mode. */ -void Sd2Card::readEnd(void) { - if (inBlock_) { - // skip data and crc -#ifdef OPTIMIZE_HARDWARE_SPI - // optimize skip for hardware - SPDR = 0XFF; - while (offset_++ < 513) { - while (!(SPSR & (1 << SPIF))); - SPDR = 0XFF; - } - // wait for last crc byte - while (!(SPSR & (1 << SPIF))); -#else // OPTIMIZE_HARDWARE_SPI - while (offset_++ < 514) spiRec(); -#endif // OPTIMIZE_HARDWARE_SPI - chipSelectHigh(); - inBlock_ = 0; - } -} -//------------------------------------------------------------------------------ -/** read CID or CSR register */ -uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { - uint8_t* dst = reinterpret_cast(buf); - if (cardCommand(cmd, 0)) { - error(SD_CARD_ERROR_READ_REG); - goto fail; - } - if (!waitStartBlock()) goto fail; - // transfer data - for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); - spiRec(); // get first crc byte - spiRec(); // get second crc byte - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Set the SPI clock rate. - * - * \param[in] sckRateID A value in the range [0, 6]. - * - * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum - * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 - * for \a scsRateID = 6. - * - * \return The value one, true, is returned for success and the value zero, - * false, is returned for an invalid value of \a sckRateID. - */ -uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { - if (sckRateID > 6) { - error(SD_CARD_ERROR_SCK_RATE); - return false; - } - // see avr processor datasheet for SPI register bit definitions - if ((sckRateID & 1) || sckRateID == 6) { - SPSR &= ~(1 << SPI2X); - } else { - SPSR |= (1 << SPI2X); - } - SPCR &= ~((1 < SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; - } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Writes a 512 byte block to an SD card. - * - * \param[in] blockNumber Logical block to be written. - * \param[in] src Pointer to the location of the data to be written. - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { -#if SD_PROTECT_BLOCK_ZERO - // don't allow write to first block - if (blockNumber == 0) { - error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); - goto fail; - } -#endif // SD_PROTECT_BLOCK_ZERO - - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD24, blockNumber)) { - error(SD_CARD_ERROR_CMD24); - goto fail; - } - if (!writeData(DATA_START_BLOCK, src)) goto fail; - - // wait for flash programming to complete - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_TIMEOUT); - goto fail; - } - // response is r2 so get and check two bytes for nonzero - if (cardCommand(CMD13, 0) || spiRec()) { - error(SD_CARD_ERROR_WRITE_PROGRAMMING); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Write one data block in a multiple block write sequence */ -uint8_t Sd2Card::writeData(const uint8_t* src) { - // wait for previous write to finish - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_MULTIPLE); - chipSelectHigh(); - return false; - } - return writeData(WRITE_MULTIPLE_TOKEN, src); -} -//------------------------------------------------------------------------------ -// send one block of data for write block or write multiple blocks -uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { -#ifdef OPTIMIZE_HARDWARE_SPI - - // send data - optimized loop - SPDR = token; - - // send two byte per iteration - for (uint16_t i = 0; i < 512; i += 2) { - while (!(SPSR & (1 << SPIF))); - SPDR = src[i]; - while (!(SPSR & (1 << SPIF))); - SPDR = src[i+1]; - } - - // wait for last data byte - while (!(SPSR & (1 << SPIF))); - -#else // OPTIMIZE_HARDWARE_SPI - spiSend(token); - for (uint16_t i = 0; i < 512; i++) { - spiSend(src[i]); - } -#endif // OPTIMIZE_HARDWARE_SPI - spiSend(0xff); // dummy crc - spiSend(0xff); // dummy crc - - status_ = spiRec(); - if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { - error(SD_CARD_ERROR_WRITE); - chipSelectHigh(); - return false; - } - return true; -} -//------------------------------------------------------------------------------ -/** Start a write multiple blocks sequence. - * - * \param[in] blockNumber Address of first block in sequence. - * \param[in] eraseCount The number of blocks to be pre-erased. - * - * \note This function is used with writeData() and writeStop() - * for optimized multiple block writes. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { -#if SD_PROTECT_BLOCK_ZERO - // don't allow write to first block - if (blockNumber == 0) { - error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); - goto fail; - } -#endif // SD_PROTECT_BLOCK_ZERO - // send pre-erase count - if (cardAcmd(ACMD23, eraseCount)) { - error(SD_CARD_ERROR_ACMD23); - goto fail; - } - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD25, blockNumber)) { - error(SD_CARD_ERROR_CMD25); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** End a write multiple blocks sequence. - * -* \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::writeStop(void) { - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - spiSend(STOP_TRAN_TOKEN); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_STOP_TRAN); - chipSelectHigh(); - return false; -} diff --git a/Tonokip_Firmware/Sd2Card.h b/Tonokip_Firmware/Sd2Card.h deleted file mode 100644 index 73b46fb..0000000 --- a/Tonokip_Firmware/Sd2Card.h +++ /dev/null @@ -1,233 +0,0 @@ -/* 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 - * . - */ -#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 diff --git a/Tonokip_Firmware/Sd2PinMap.h b/Tonokip_Firmware/Sd2PinMap.h deleted file mode 100644 index 4bd75a3..0000000 --- a/Tonokip_Firmware/Sd2PinMap.h +++ /dev/null @@ -1,353 +0,0 @@ -/* 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 - * . - */ -// Warning this file was generated by a program. -#ifndef Sd2PinMap_h -#define Sd2PinMap_h -#include - -//------------------------------------------------------------------------------ -/** 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 diff --git a/Tonokip_Firmware/SdFat.h b/Tonokip_Firmware/SdFat.h deleted file mode 100644 index 048fa71..0000000 --- a/Tonokip_Firmware/SdFat.h +++ /dev/null @@ -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 - * . - */ -#ifndef SdFat_h -#define SdFat_h -/** - * \file - * SdFile and SdVolume classes - */ -#include -#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 diff --git a/Tonokip_Firmware/SdFatUtil.h b/Tonokip_Firmware/SdFatUtil.h deleted file mode 100644 index 8bf9048..0000000 --- a/Tonokip_Firmware/SdFatUtil.h +++ /dev/null @@ -1,70 +0,0 @@ -/* 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 - * . - */ -#ifndef SdFatUtil_h -#define SdFatUtil_h -/** - * \file - * Useful utility functions. - */ -#include -#include -/** 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(__brkval) == 0) { - // if no heap use from end of bss section - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(&__bss_end); - } else { - // use from top of stack to heap - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(__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 diff --git a/Tonokip_Firmware/SdFatmainpage.h b/Tonokip_Firmware/SdFatmainpage.h deleted file mode 100644 index 73b3b63..0000000 --- a/Tonokip_Firmware/SdFatmainpage.h +++ /dev/null @@ -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 - * . - */ - -/** -\mainpage Arduino SdFat Library -
Copyright © 2009 by William Greiman -
- -\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 - Adafruit Industries - Wave Shield. - -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 - - - */ diff --git a/Tonokip_Firmware/SdFile.cpp b/Tonokip_Firmware/SdFile.cpp deleted file mode 100644 index 0a27159..0000000 --- a/Tonokip_Firmware/SdFile.cpp +++ /dev/null @@ -1,1252 +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 - * . - */ -#include "SdFat.h" -#include -#include -//------------------------------------------------------------------------------ -// callback function for date/time -void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; - -#if ALLOW_DEPRECATED_FUNCTIONS -// suppress cpplint warnings with NOLINT comment -void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT -#endif // ALLOW_DEPRECATED_FUNCTIONS -//------------------------------------------------------------------------------ -// add a cluster to a file -uint8_t SdFile::addCluster() { - if (!vol_->allocContiguous(1, &curCluster_)) return false; - - // if first cluster of file link to directory entry - if (firstCluster_ == 0) { - firstCluster_ = curCluster_; - flags_ |= F_FILE_DIR_DIRTY; - } - return true; -} -//------------------------------------------------------------------------------ -// Add a cluster to a directory file and zero the cluster. -// return with first block of cluster in the cache -uint8_t SdFile::addDirCluster(void) { - if (!addCluster()) return false; - - // zero data in cluster insure first cluster is in cache - uint32_t block = vol_->clusterStartBlock(curCluster_); - for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { - if (!SdVolume::cacheZeroBlock(block + i - 1)) return false; - } - // Increase directory file size by cluster size - fileSize_ += 512UL << vol_->clusterSizeShift_; - return true; -} -//------------------------------------------------------------------------------ -// cache a file's directory entry -// return pointer to cached entry or null for failure -dir_t* SdFile::cacheDirEntry(uint8_t action) { - if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; - return SdVolume::cacheBuffer_.dir + dirIndex_; -} -//------------------------------------------------------------------------------ -/** - * Close a file and force cached data and directory information - * to be written to the storage device. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include no file is open or an I/O error. - */ -uint8_t SdFile::close(void) { - if (!sync())return false; - type_ = FAT_FILE_TYPE_CLOSED; - return true; -} -//------------------------------------------------------------------------------ -/** - * Check for contiguous file and return its raw block range. - * - * \param[out] bgnBlock the first block address for the file. - * \param[out] endBlock the last block address for the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include file is not contiguous, file has zero length - * or an I/O error occurred. - */ -uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { - // error if no blocks - if (firstCluster_ == 0) return false; - - for (uint32_t c = firstCluster_; ; c++) { - uint32_t next; - if (!vol_->fatGet(c, &next)) return false; - - // check for contiguous - if (next != (c + 1)) { - // error if not end of chain - if (!vol_->isEOC(next)) return false; - *bgnBlock = vol_->clusterStartBlock(firstCluster_); - *endBlock = vol_->clusterStartBlock(c) - + vol_->blocksPerCluster_ - 1; - return true; - } - } -} -//------------------------------------------------------------------------------ -/** - * Create and open a new contiguous file of a specified size. - * - * \note This function only supports short DOS 8.3 names. - * See open() for more information. - * - * \param[in] dirFile The directory where the file will be created. - * \param[in] fileName A valid DOS 8.3 file name. - * \param[in] size The desired file size. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include \a fileName contains - * an invalid DOS 8.3 file name, the FAT volume has not been initialized, - * a file is already open, the file already exists, the root - * directory is full or an I/O error. - * - */ -uint8_t SdFile::createContiguous(SdFile* dirFile, - const char* fileName, uint32_t size) { - // don't allow zero length file - if (size == 0) return false; - if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false; - - // calculate number of clusters needed - uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; - - // allocate clusters - if (!vol_->allocContiguous(count, &firstCluster_)) { - remove(); - return false; - } - fileSize_ = size; - - // insure sync() will update dir entry - flags_ |= F_FILE_DIR_DIRTY; - return sync(); -} -//------------------------------------------------------------------------------ -/** - * Return a files directory entry - * - * \param[out] dir Location for return of the files directory entry. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::dirEntry(dir_t* dir) { - // make sure fields on SD are correct - if (!sync()) return false; - - // read entry - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); - if (!p) return false; - - // copy to caller's struct - memcpy(dir, p, sizeof(dir_t)); - return true; -} -//------------------------------------------------------------------------------ -/** - * Format the name field of \a dir into the 13 byte array - * \a name in standard 8.3 short name format. - * - * \param[in] dir The directory structure containing the name. - * \param[out] name A 13 byte char array for the formatted name. - */ -void SdFile::dirName(const dir_t& dir, char* name) { - uint8_t j = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) name[j++] = '.'; - name[j++] = dir.name[i]; - } - name[j] = 0; -} -//------------------------------------------------------------------------------ -/** List directory contents to Serial. - * - * \param[in] flags The inclusive OR of - * - * LS_DATE - %Print file modification date - * - * LS_SIZE - %Print file size. - * - * LS_R - Recursive list of subdirectories. - * - * \param[in] indent Amount of space before file name. Used for recursive - * list to indicate subdirectory level. - */ -void SdFile::ls(uint8_t flags, uint8_t indent) { - dir_t* p; - - rewind(); - while ((p = readDirCache())) { - // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) break; - - // skip deleted entry and entries for . and .. - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; - - // print any indent spaces - for (int8_t i = 0; i < indent; i++) Serial.print(' '); - - // print file name with possible blank fill - printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); - - // print modify date/time if requested - if (flags & LS_DATE) { - printFatDate(p->lastWriteDate); - Serial.print(' '); - printFatTime(p->lastWriteTime); - } - // print size if requested - if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { - Serial.print(' '); - Serial.print(p->fileSize); - } - Serial.println(); - - // list subdirectory content if requested - if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { - uint16_t index = curPosition()/32 - 1; - SdFile s; - if (s.open(this, index, O_READ)) s.ls(flags, indent + 2); - seekSet(32 * (index + 1)); - } - } -} -//------------------------------------------------------------------------------ -// format directory name field from a 8.3 name string -uint8_t SdFile::make83Name(const char* str, uint8_t* name) { - uint8_t c; - uint8_t n = 7; // max index for part before dot - uint8_t i = 0; - // blank fill name and extension - while (i < 11) name[i++] = ' '; - i = 0; - while ((c = *str++) != '\0') { - if (c == '.') { - if (n == 10) return false; // only one dot allowed - n = 10; // max index for full 8.3 name - i = 8; // place for extension - } else { - // illegal FAT characters - PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); - uint8_t b; - while ((b = pgm_read_byte(p++))) if (b == c) return false; - // check size and only allow ASCII printable characters - if (i > n || c < 0X21 || c > 0X7E)return false; - // only upper case allowed in 8.3 names - convert lower to upper - name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); - } - } - // must have a file name, extension is optional - return name[0] != ' '; -} -//------------------------------------------------------------------------------ -/** Make a new directory. - * - * \param[in] dir An open SdFat instance for the directory that will containing - * the new directory. - * - * \param[in] dirName A valid 8.3 DOS name for the new directory. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include this SdFile is already open, \a dir is not a - * directory, \a dirName is invalid or already exists in \a dir. - */ -uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { - dir_t d; - - // create a normal file - if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false; - - // convert SdFile to directory - flags_ = O_READ; - type_ = FAT_FILE_TYPE_SUBDIR; - - // allocate and zero first cluster - if (!addDirCluster())return false; - - // force entry to SD - if (!sync()) return false; - - // cache entry - should already be in cache due to sync() call - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) return false; - - // change directory entry attribute - p->attributes = DIR_ATT_DIRECTORY; - - // make entry for '.' - memcpy(&d, p, sizeof(d)); - for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; - d.name[0] = '.'; - - // cache block for '.' and '..' - uint32_t block = vol_->clusterStartBlock(firstCluster_); - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; - - // copy '.' to block - memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); - - // make entry for '..' - d.name[1] = '.'; - if (dir->isRoot()) { - d.firstClusterLow = 0; - d.firstClusterHigh = 0; - } else { - d.firstClusterLow = dir->firstCluster_ & 0XFFFF; - d.firstClusterHigh = dir->firstCluster_ >> 16; - } - // copy '..' to block - memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); - - // set position after '..' - curPosition_ = 2 * sizeof(d); - - // write first block - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Open a file or directory by name. - * - * \param[in] dirFile An open SdFat instance for the directory containing the - * file to be opened. - * - * \param[in] fileName A valid 8.3 DOS name for a file to be opened. - * - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of flags from the following list - * - * O_READ - Open for reading. - * - * O_RDONLY - Same as O_READ. - * - * O_WRITE - Open for writing. - * - * O_WRONLY - Same as O_WRITE. - * - * O_RDWR - Open for reading and writing. - * - * O_APPEND - If set, the file offset shall be set to the end of the - * file prior to each write. - * - * O_CREAT - If the file exists, this flag has no effect except as noted - * under O_EXCL below. Otherwise, the file shall be created - * - * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. - * - * O_SYNC - Call sync() after each write. This flag should not be used with - * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. - * These functions do character at a time writes so sync() will be called - * after each byte. - * - * O_TRUNC - If the file exists and is a regular file, and the file is - * successfully opened and is not read only, its length shall be truncated to 0. - * - * \note Directory files must be opened read only. Write and truncation is - * not allowed for directory files. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include this SdFile is already open, \a difFile is not - * a directory, \a fileName is invalid, the file does not exist - * or can't be opened in the access mode specified by oflag. - */ -uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { - uint8_t dname[11]; - dir_t* p; - - // error if already open - if (isOpen())return false; - - if (!make83Name(fileName, dname)) return false; - vol_ = dirFile->vol_; - dirFile->rewind(); - - // bool for empty entry found - uint8_t emptyFound = false; - - // search for file - while (dirFile->curPosition_ < dirFile->fileSize_) { - uint8_t index = 0XF & (dirFile->curPosition_ >> 5); - p = dirFile->readDirCache(); - if (p == NULL) return false; - - if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { - // remember first empty slot - if (!emptyFound) { - emptyFound = true; - dirIndex_ = index; - dirBlock_ = SdVolume::cacheBlockNumber_; - } - // done if no entries follow - if (p->name[0] == DIR_NAME_FREE) break; - } else if (!memcmp(dname, p->name, 11)) { - // don't open existing file if O_CREAT and O_EXCL - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; - - // open found file - return openCachedEntry(0XF & index, oflag); - } - } - // only create file if O_CREAT and O_WRITE - if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; - - // cache found slot or add cluster if end of file - if (emptyFound) { - p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) return false; - } else { - if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false; - - // add and zero cluster for dirFile - first cluster is in cache for write - if (!dirFile->addDirCluster()) return false; - - // use first entry in cluster - dirIndex_ = 0; - p = SdVolume::cacheBuffer_.dir; - } - // initialize as empty file - memset(p, 0, sizeof(dir_t)); - memcpy(p->name, dname, 11); - - // set timestamps - if (dateTime_) { - // call user function - dateTime_(&p->creationDate, &p->creationTime); - } else { - // use default date/time - p->creationDate = FAT_DEFAULT_DATE; - p->creationTime = FAT_DEFAULT_TIME; - } - p->lastAccessDate = p->creationDate; - p->lastWriteDate = p->creationDate; - p->lastWriteTime = p->creationTime; - - // force write of entry to SD - if (!SdVolume::cacheFlush()) return false; - - // open entry in cache - return openCachedEntry(dirIndex_, oflag); -} -//------------------------------------------------------------------------------ -/** - * Open a file by index. - * - * \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. - * - * See open() by fileName for definition of flags and return values. - * - */ -uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { - // error if already open - if (isOpen())return false; - - // don't open existing file if O_CREAT and O_EXCL - user call error - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; - - vol_ = dirFile->vol_; - - // seek to location of entry - if (!dirFile->seekSet(32 * index)) return false; - - // read entry into cache - dir_t* p = dirFile->readDirCache(); - if (p == NULL) return false; - - // error if empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_FREE || - p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { - return false; - } - // open cached entry - return openCachedEntry(index & 0XF, oflag); -} -//------------------------------------------------------------------------------ -// open a cached directory entry. Assumes vol_ is initializes -uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { - // location of entry in cache - dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; - - // write or truncate is an error for a directory or read-only file - if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { - if (oflag & (O_WRITE | O_TRUNC)) return false; - } - // remember location of directory entry on SD - dirIndex_ = dirIndex; - dirBlock_ = SdVolume::cacheBlockNumber_; - - // copy first cluster number for directory fields - firstCluster_ = (uint32_t)p->firstClusterHigh << 16; - firstCluster_ |= p->firstClusterLow; - - // make sure it is a normal file or subdirectory - if (DIR_IS_FILE(p)) { - fileSize_ = p->fileSize; - type_ = FAT_FILE_TYPE_NORMAL; - } else if (DIR_IS_SUBDIR(p)) { - if (!vol_->chainSize(firstCluster_, &fileSize_)) return false; - type_ = FAT_FILE_TYPE_SUBDIR; - } else { - return false; - } - // save open flags for read/write - flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - - // truncate file to zero length if requested - if (oflag & O_TRUNC) return truncate(0); - return true; -} -//------------------------------------------------------------------------------ -/** - * Open a volume's root directory. - * - * \param[in] vol The FAT volume containing the root directory to be opened. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the FAT volume has not been initialized - * or it a FAT12 volume. - */ -uint8_t SdFile::openRoot(SdVolume* vol) { - // error if file is already open - if (isOpen()) return false; - - if (vol->fatType() == 16) { - type_ = FAT_FILE_TYPE_ROOT16; - firstCluster_ = 0; - fileSize_ = 32 * vol->rootDirEntryCount(); - } else if (vol->fatType() == 32) { - type_ = FAT_FILE_TYPE_ROOT32; - firstCluster_ = vol->rootDirStart(); - if (!vol->chainSize(firstCluster_, &fileSize_)) return false; - } else { - // volume is not initialized or FAT12 - return false; - } - vol_ = vol; - // read only - flags_ = O_READ; - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - - // root has no directory entry - dirBlock_ = 0; - dirIndex_ = 0; - return true; -} -//------------------------------------------------------------------------------ -/** %Print the name field of a directory entry in 8.3 format to Serial. - * - * \param[in] dir The directory structure containing the name. - * \param[in] width Blank fill name if length is less than \a width. - */ -void SdFile::printDirName(const dir_t& dir, uint8_t width) { - uint8_t w = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) { - Serial.print('.'); - w++; - } - Serial.print(dir.name[i]); - w++; - } - if (DIR_IS_SUBDIR(&dir)) { - Serial.print('/'); - w++; - } - while (w < width) { - Serial.print(' '); - w++; - } -} -//------------------------------------------------------------------------------ -/** %Print a directory date field to Serial. - * - * Format is yyyy-mm-dd. - * - * \param[in] fatDate The date field from a directory entry. - */ -void SdFile::printFatDate(uint16_t fatDate) { - Serial.print(FAT_YEAR(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_MONTH(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_DAY(fatDate)); -} -//------------------------------------------------------------------------------ -/** %Print a directory time field to Serial. - * - * Format is hh:mm:ss. - * - * \param[in] fatTime The time field from a directory entry. - */ -void SdFile::printFatTime(uint16_t fatTime) { - printTwoDigits(FAT_HOUR(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_MINUTE(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_SECOND(fatTime)); -} -//------------------------------------------------------------------------------ -/** %Print a value as two digits to Serial. - * - * \param[in] v Value to be printed, 0 <= \a v <= 99 - */ -void SdFile::printTwoDigits(uint8_t v) { - char str[3]; - str[0] = '0' + v/10; - str[1] = '0' + v % 10; - str[2] = 0; - Serial.print(str); -} -//------------------------------------------------------------------------------ -/** - * Read data from a file starting at the current position. - * - * \param[out] buf Pointer to the location that will receive the data. - * - * \param[in] nbyte Maximum number of bytes to read. - * - * \return For success read() returns the number of bytes read. - * A value less than \a nbyte, including zero, will be returned - * if end of file is reached. - * If an error occurs, read() returns -1. Possible errors include - * read() called before a file has been opened, corrupt file system - * or an I/O error occurred. - */ -int16_t SdFile::read(void* buf, uint16_t nbyte) { - uint8_t* dst = reinterpret_cast(buf); - - // error if not open or write only - if (!isOpen() || !(flags_ & O_READ)) return -1; - - // max bytes left in file - if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; - - // amount left to read - uint16_t toRead = nbyte; - while (toRead > 0) { - uint32_t block; // raw device block number - uint16_t offset = curPosition_ & 0X1FF; // offset in block - if (type_ == FAT_FILE_TYPE_ROOT16) { - block = vol_->rootDirStart() + (curPosition_ >> 9); - } else { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - if (offset == 0 && blockOfCluster == 0) { - // start of new cluster - if (curPosition_ == 0) { - // use first cluster in file - curCluster_ = firstCluster_; - } else { - // get next cluster from FAT - if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; - } - } - block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - } - uint16_t n = toRead; - - // amount to be read from current block - if (n > (512 - offset)) n = 512 - offset; - - // no buffering needed if n == 512 or user requests no buffering - if ((unbufferedRead() || n == 512) && - block != SdVolume::cacheBlockNumber_) { - if (!vol_->readData(block, offset, n, dst)) return -1; - dst += n; - } else { - // read block to cache and copy data to caller - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1; - uint8_t* src = SdVolume::cacheBuffer_.data + offset; - uint8_t* end = src + n; - while (src != end) *dst++ = *src++; - } - curPosition_ += n; - toRead -= n; - } - return nbyte; -} -//------------------------------------------------------------------------------ -/** - * Read the next directory entry from a directory file. - * - * \param[out] dir The dir_t struct that will receive the data. - * - * \return For success readDir() returns the number of bytes read. - * A value of zero will be returned if end of file is reached. - * If an error occurs, readDir() returns -1. Possible errors include - * readDir() called before a directory has been opened, this is not - * a directory file or an I/O error occurred. - */ -int8_t SdFile::readDir(dir_t* dir) { - int8_t n; - // if not a directory file or miss-positioned return an error - if (!isDir() || (0X1F & curPosition_)) return -1; - - while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { - // last entry if DIR_NAME_FREE - if (dir->name[0] == DIR_NAME_FREE) break; - // skip empty entries and entry for . and .. - if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; - // return if normal file or subdirectory - if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; - } - // error, end of file, or past last entry - return n < 0 ? -1 : 0; -} -//------------------------------------------------------------------------------ -// Read next directory entry into the cache -// Assumes file is correctly positioned -dir_t* SdFile::readDirCache(void) { - // error if not directory - if (!isDir()) return NULL; - - // index of entry in cache - uint8_t i = (curPosition_ >> 5) & 0XF; - - // use read to locate and cache block - if (read() < 0) return NULL; - - // advance to next entry - curPosition_ += 31; - - // return pointer to entry - return (SdVolume::cacheBuffer_.dir + i); -} -//------------------------------------------------------------------------------ -/** - * Remove a file. - * - * The directory entry and all data for the file are deleted. - * - * \note This function should not be used to delete the 8.3 version of a - * file that has a long name. For example if a file has the long name - * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file read-only, is a directory, - * or an I/O error occurred. - */ -uint8_t SdFile::remove(void) { - // free any clusters - will fail if read-only or directory - if (!truncate(0)) return false; - - // cache directory entry - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - // mark entry deleted - d->name[0] = DIR_NAME_DELETED; - - // set this SdFile closed - type_ = FAT_FILE_TYPE_CLOSED; - - // write entry to SD - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Remove a file. - * - * The directory entry and all data for the file are deleted. - * - * \param[in] dirFile The directory that contains the file. - * \param[in] fileName The name of the file to be removed. - * - * \note This function should not be used to delete the 8.3 version of a - * file that has a long name. For example if a file has the long name - * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file is a directory, is read only, - * \a dirFile is not a directory, \a fileName is not found - * or an I/O error occurred. - */ -uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { - SdFile file; - if (!file.open(dirFile, fileName, O_WRITE)) return false; - return file.remove(); -} -//------------------------------------------------------------------------------ -/** Remove a directory file. - * - * The directory file will be removed only if it is empty and is not the - * root directory. rmDir() follows DOS and Windows and ignores the - * read-only attribute for the directory. - * - * \note This function should not be used to delete the 8.3 version of a - * directory that has a long name. For example if a directory has the - * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file is not a directory, is the root - * directory, is not empty, or an I/O error occurred. - */ -uint8_t SdFile::rmDir(void) { - // must be open subdirectory - if (!isSubDir()) return false; - - rewind(); - - // make sure directory is empty - while (curPosition_ < fileSize_) { - dir_t* p = readDirCache(); - if (p == NULL) return false; - // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) break; - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - // error not empty - if (DIR_IS_FILE_OR_SUBDIR(p)) return false; - } - // convert empty directory to normal file for remove - type_ = FAT_FILE_TYPE_NORMAL; - flags_ |= O_WRITE; - return remove(); -} -//------------------------------------------------------------------------------ -/** Recursively delete a directory and all contained files. - * - * This is like the Unix/Linux 'rm -rf *' if called with the root directory - * hence the name. - * - * Warning - This will remove all contents of the directory including - * subdirectories. The directory will then be removed if it is not root. - * The read-only attribute for files will be ignored. - * - * \note This function should not be used to delete the 8.3 version of - * a directory that has a long name. See remove() and rmDir(). - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::rmRfStar(void) { - rewind(); - while (curPosition_ < fileSize_) { - SdFile f; - - // remember position - uint16_t index = curPosition_/32; - - dir_t* p = readDirCache(); - if (!p) return false; - - // done if past last entry - if (p->name[0] == DIR_NAME_FREE) break; - - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - - // skip if part of long file name or volume label in root - if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; - - if (!f.open(this, index, O_READ)) return false; - if (f.isSubDir()) { - // recursively delete - if (!f.rmRfStar()) return false; - } else { - // ignore read-only - f.flags_ |= O_WRITE; - if (!f.remove()) return false; - } - // position to next entry if required - if (curPosition_ != (32*(index + 1))) { - if (!seekSet(32*(index + 1))) return false; - } - } - // don't try to delete root - if (isRoot()) return true; - return rmDir(); -} -//------------------------------------------------------------------------------ -/** - * Sets a file's position. - * - * \param[in] pos The new position in bytes from the beginning of the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::seekSet(uint32_t pos) { - // error if file not open or seek past end of file - if (!isOpen() || pos > fileSize_) return false; - - if (type_ == FAT_FILE_TYPE_ROOT16) { - curPosition_ = pos; - return true; - } - if (pos == 0) { - // set position to start of file - curCluster_ = 0; - curPosition_ = 0; - return true; - } - // calculate cluster index for cur and new position - uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); - uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); - - if (nNew < nCur || curPosition_ == 0) { - // must follow chain from first cluster - curCluster_ = firstCluster_; - } else { - // advance from curPosition - nNew -= nCur; - } - while (nNew--) { - if (!vol_->fatGet(curCluster_, &curCluster_)) return false; - } - curPosition_ = pos; - return true; -} -//------------------------------------------------------------------------------ -/** - * The sync() call causes all modified data and directory fields - * to be written to the storage device. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include a call to sync() before a file has been - * opened or an I/O error. - */ -uint8_t SdFile::sync(void) { - // only allow open files and directories - if (!isOpen()) return false; - - if (flags_ & F_FILE_DIR_DIRTY) { - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - // do not set filesize for dir files - if (!isDir()) d->fileSize = fileSize_; - - // update first cluster fields - d->firstClusterLow = firstCluster_ & 0XFFFF; - d->firstClusterHigh = firstCluster_ >> 16; - - // set modify time if user supplied a callback date/time function - if (dateTime_) { - dateTime_(&d->lastWriteDate, &d->lastWriteTime); - d->lastAccessDate = d->lastWriteDate; - } - // clear directory dirty - flags_ &= ~F_FILE_DIR_DIRTY; - } - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Set a file's timestamps in its directory entry. - * - * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive - * OR of flags from the following list - * - * T_ACCESS - Set the file's last access date. - * - * T_CREATE - Set the file's creation date and time. - * - * T_WRITE - Set the file's last write/modification date and time. - * - * \param[in] year Valid range 1980 - 2107 inclusive. - * - * \param[in] month Valid range 1 - 12 inclusive. - * - * \param[in] day Valid range 1 - 31 inclusive. - * - * \param[in] hour Valid range 0 - 23 inclusive. - * - * \param[in] minute Valid range 0 - 59 inclusive. - * - * \param[in] second Valid range 0 - 59 inclusive - * - * \note It is possible to set an invalid date since there is no check for - * the number of days in a month. - * - * \note - * Modify and access timestamps may be overwritten if a date time callback - * function has been set by dateTimeCallback(). - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, - uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { - if (!isOpen() - || year < 1980 - || year > 2107 - || month < 1 - || month > 12 - || day < 1 - || day > 31 - || hour > 23 - || minute > 59 - || second > 59) { - return false; - } - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - uint16_t dirDate = FAT_DATE(year, month, day); - uint16_t dirTime = FAT_TIME(hour, minute, second); - if (flags & T_ACCESS) { - d->lastAccessDate = dirDate; - } - if (flags & T_CREATE) { - d->creationDate = dirDate; - d->creationTime = dirTime; - // seems to be units of 1/100 second not 1/10 as Microsoft states - d->creationTimeTenths = second & 1 ? 100 : 0; - } - if (flags & T_WRITE) { - d->lastWriteDate = dirDate; - d->lastWriteTime = dirTime; - } - SdVolume::cacheSetDirty(); - return sync(); -} -//------------------------------------------------------------------------------ -/** - * Truncate a file to a specified length. The current file position - * will be maintained if it is less than or equal to \a length otherwise - * it will be set to end of file. - * - * \param[in] length The desired length for the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include file is read only, file is a directory, - * \a length is greater than the current file size or an I/O error occurs. - */ -uint8_t SdFile::truncate(uint32_t length) { -// error if not a normal file or read-only - if (!isFile() || !(flags_ & O_WRITE)) return false; - - // error if length is greater than current size - if (length > fileSize_) return false; - - // fileSize and length are zero - nothing to do - if (fileSize_ == 0) return true; - - // remember position for seek after truncation - uint32_t newPos = curPosition_ > length ? length : curPosition_; - - // position to last cluster in truncated file - if (!seekSet(length)) return false; - - if (length == 0) { - // free all clusters - if (!vol_->freeChain(firstCluster_)) return false; - firstCluster_ = 0; - } else { - uint32_t toFree; - if (!vol_->fatGet(curCluster_, &toFree)) return false; - - if (!vol_->isEOC(toFree)) { - // free extra clusters - if (!vol_->freeChain(toFree)) return false; - - // current cluster is end of chain - if (!vol_->fatPutEOC(curCluster_)) return false; - } - } - fileSize_ = length; - - // need to update directory entry - flags_ |= F_FILE_DIR_DIRTY; - - if (!sync()) return false; - - // set file to correct position - return seekSet(newPos); -} -//------------------------------------------------------------------------------ -/** - * Write data to an open file. - * - * \note Data is moved to the cache but may not be written to the - * storage device until sync() is called. - * - * \param[in] buf Pointer to the location of the data to be written. - * - * \param[in] nbyte Number of bytes to write. - * - * \return For success write() returns the number of bytes written, always - * \a nbyte. If an error occurs, write() returns -1. Possible errors - * include write() is called before a file has been opened, write is called - * for a read-only file, device is full, a corrupt file system or an I/O error. - * - */ -int16_t SdFile::write(const void* buf, uint16_t nbyte) { - // convert void* to uint8_t* - must be before goto statements - const uint8_t* src = reinterpret_cast(buf); - - // number of bytes left to write - must be before goto statements - uint16_t nToWrite = nbyte; - - // error if not a normal file or is read-only - if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; - - // seek to end of file if append flag - if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { - if (!seekEnd()) goto writeErrorReturn; - } - - while (nToWrite > 0) { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - uint16_t blockOffset = curPosition_ & 0X1FF; - if (blockOfCluster == 0 && blockOffset == 0) { - // start of new cluster - if (curCluster_ == 0) { - if (firstCluster_ == 0) { - // allocate first cluster of file - if (!addCluster()) goto writeErrorReturn; - } else { - curCluster_ = firstCluster_; - } - } else { - uint32_t next; - if (!vol_->fatGet(curCluster_, &next)) return false; - if (vol_->isEOC(next)) { - // add cluster if at end of chain - if (!addCluster()) goto writeErrorReturn; - } else { - curCluster_ = next; - } - } - } - // max space in block - uint16_t n = 512 - blockOffset; - - // lesser of space and amount to write - if (n > nToWrite) n = nToWrite; - - // block for data write - uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - if (n == 512) { - // full block - don't need to use cache - // invalidate cache if block is in cache - if (SdVolume::cacheBlockNumber_ == block) { - SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; - } - if (!vol_->writeBlock(block, src)) goto writeErrorReturn; - src += 512; - } else { - if (blockOffset == 0 && curPosition_ >= fileSize_) { - // start of new block don't need to read into cache - if (!SdVolume::cacheFlush()) goto writeErrorReturn; - SdVolume::cacheBlockNumber_ = block; - SdVolume::cacheSetDirty(); - } else { - // rewrite part of block - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { - goto writeErrorReturn; - } - } - uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; - uint8_t* end = dst + n; - while (dst != end) *dst++ = *src++; - } - nToWrite -= n; - curPosition_ += n; - } - if (curPosition_ > fileSize_) { - // update fileSize and insure sync will update dir entry - fileSize_ = curPosition_; - flags_ |= F_FILE_DIR_DIRTY; - } else if (dateTime_ && nbyte) { - // insure sync will update modified date and time - flags_ |= F_FILE_DIR_DIRTY; - } - - if (flags_ & O_SYNC) { - if (!sync()) goto writeErrorReturn; - } - return nbyte; - - writeErrorReturn: - // return for write error - writeError = true; - return -1; -} -//------------------------------------------------------------------------------ -/** - * Write a byte to a file. Required by the Arduino Print class. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::write(uint8_t b) { - write(&b, 1); -} -//------------------------------------------------------------------------------ -/** - * Write a string to a file. Used by the Arduino Print class. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::write(const char* str) { - write(str, strlen(str)); -} -//------------------------------------------------------------------------------ -/** - * Write a PROGMEM string to a file. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::write_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); -} -//------------------------------------------------------------------------------ -/** - * Write a PROGMEM string followed by CR/LF to a file. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::writeln_P(PGM_P str) { - write_P(str); - println(); -} diff --git a/Tonokip_Firmware/SdInfo.h b/Tonokip_Firmware/SdInfo.h deleted file mode 100644 index acde74d..0000000 --- a/Tonokip_Firmware/SdInfo.h +++ /dev/null @@ -1,232 +0,0 @@ -/* 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 - * . - */ -#ifndef SdInfo_h -#define SdInfo_h -#include -// 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 diff --git a/Tonokip_Firmware/SdVolume.cpp b/Tonokip_Firmware/SdVolume.cpp deleted file mode 100644 index 3c1e641..0000000 --- a/Tonokip_Firmware/SdVolume.cpp +++ /dev/null @@ -1,295 +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 - * . - */ -#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; -} diff --git a/Tonokip_Firmware/ThermistorTable_100k.h b/Tonokip_Firmware/ThermistorTable_100k.h deleted file mode 100644 index d0698b2..0000000 --- a/Tonokip_Firmware/ThermistorTable_100k.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef THERMISTORTABLE_H_ -#define THERMISTORTABLE_H_ - -// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) -// See this page: -// http://dev.www.reprap.org/bin/view/Main/Thermistor -// for details of what goes in this table. -// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) -// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 -// r0: 100000 -// t0: 25 -// r1: 0 -// r2: 4700 -// beta: 4066 -// max adc: 1023 - -#define NUMTEMPS 61 -const short temptable[NUMTEMPS][2] = { -{ 23 , 300 }, -{ 25 , 295 }, -{ 27 , 290 }, -{ 28 , 285 }, -{ 31 , 280 }, -{ 33 , 275 }, -{ 35 , 270 }, -{ 38 , 265 }, -{ 41 , 260 }, -{ 44 , 255 }, -{ 48 , 250 }, -{ 52 , 245 }, -{ 56 , 240 }, -{ 61 , 235 }, -{ 66 , 230 }, -{ 71 , 225 }, -{ 78 , 220 }, -{ 84 , 215 }, -{ 92 , 210 }, -{ 100 , 205 }, -{ 109 , 200 }, -{ 120 , 195 }, -{ 131 , 190 }, -{ 143 , 185 }, -{ 156 , 180 }, -{ 171 , 175 }, -{ 187 , 170 }, -{ 205 , 165 }, -{ 224 , 160 }, -{ 245 , 155 }, -{ 268 , 150 }, -{ 293 , 145 }, -{ 320 , 140 }, -{ 348 , 135 }, -{ 379 , 130 }, -{ 411 , 125 }, -{ 445 , 120 }, -{ 480 , 115 }, -{ 516 , 110 }, -{ 553 , 105 }, -{ 591 , 100 }, -{ 628 , 95 }, -{ 665 , 90 }, -{ 702 , 85 }, -{ 737 , 80 }, -{ 770 , 75 }, -{ 801 , 70 }, -{ 830 , 65 }, -{ 857 , 60 }, -{ 881 , 55 }, -{ 903 , 50 }, -{ 922 , 45 }, -{ 939 , 40 }, -{ 954 , 35 }, -{ 966 , 30 }, -{ 977 , 25 }, -{ 985 , 20 }, -{ 993 , 15 }, -{ 999 , 10 }, -{ 1004 , 5 }, -{ 1008 , 0 }, - -}; - - -#endif - diff --git a/Tonokip_Firmware/ThermistorTable_200k.h b/Tonokip_Firmware/ThermistorTable_200k.h deleted file mode 100644 index 4142eb2..0000000 --- a/Tonokip_Firmware/ThermistorTable_200k.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef THERMISTORTABLE_H_ -#define THERMISTORTABLE_H_ - -// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts) -// See this page: -// http://dev.www.reprap.org/bin/view/Main/Thermistor -// for details of what goes in this table. -// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py) -// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=4066 --max-adc=1023 -// r0: 100000 -// t0: 25 -// r1: 0 -// r2: 4700 -// beta: 4066 -// max adc: 1023 - -#define NUMTEMPS 20 -const short temptable[NUMTEMPS][2] = { - {1, 848}, - {54, 275}, - {107, 228}, - {160, 202}, - {213, 185}, - {266, 171}, - {319, 160}, - {372, 150}, - {425, 141}, - {478, 133}, - {531, 125}, - {584, 118}, - {637, 110}, - {690, 103}, - {743, 95}, - {796, 86}, - {849, 77}, - {902, 65}, - {955, 49}, - {1008, 17} -}; - - -#endif diff --git a/Tonokip_Firmware/ThermistorTable_mendelparts.h b/Tonokip_Firmware/ThermistorTable_mendelparts.h deleted file mode 100644 index 9e65b85..0000000 --- a/Tonokip_Firmware/ThermistorTable_mendelparts.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef THERMISTORTABLE_H_ -#define THERMISTORTABLE_H_ - -//thermistor table for mendel-parts thermistor -// Standardized R/T characteristic no. 8404 - // RS thermistor 484-0183; EPCOS NTC - // Mendel-Parts thermistor G540 / G550 - // Optimized for 100...300C working range. - // Max range: -20...300C - // Max reading error on Gen 6 electronics: ~+5%, -3% in 100 - 300C range. - -#define NUMTEMPS 28 -const short temptable[NUMTEMPS][2] = { - {1,864}, - {21,300}, - {25,290}, - {29,280}, - {33,270}, - {39,260}, - {46,250}, - {54,240}, - {64,230}, - {75,220}, - {90,210}, - {107,200}, - {128,190}, - {154,180}, - {184,170}, - {221,160}, - {265,150}, - {316,140}, - {375,130}, - {441,120}, - {513,110}, - {588,100}, - {734,80}, - {856,60}, - {938,40}, - {986,20}, - {1008,0}, - {1018,-20} - }; - - -#endif diff --git a/Tonokip_Firmware/Tonokip_Firmware.h b/Tonokip_Firmware/Tonokip_Firmware.h deleted file mode 100644 index 4e3c7ea..0000000 --- a/Tonokip_Firmware/Tonokip_Firmware.h +++ /dev/null @@ -1,36 +0,0 @@ -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL -#include - -void get_command(); -void process_commands(); - -void manage_inactivity(byte debug); - -void manage_heater(); -float temp2analog(int celsius); -float temp2analogBed(int celsius); -float analog2temp(int raw); -float analog2tempBed(int raw); - -void FlushSerialRequestResend(); -void ClearToSend(); - -void get_coordinates(); -void prepare_move(); -void linear_move(unsigned long x_steps_remaining, unsigned long y_steps_remaining, unsigned long z_steps_remaining, unsigned long e_steps_remaining); -void disable_x(); -void disable_y(); -void disable_z(); -void disable_e(); -void enable_x(); -void enable_y(); -void enable_z(); -void enable_e(); -void do_x_step(); -void do_y_step(); -void do_z_step(); -void do_e_step(); - -void kill(byte debug); - diff --git a/Tonokip_Firmware/Tonokip_Firmware.pde b/Tonokip_Firmware/Tonokip_Firmware.pde deleted file mode 100644 index 4528324..0000000 --- a/Tonokip_Firmware/Tonokip_Firmware.pde +++ /dev/null @@ -1,1548 +0,0 @@ -// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware. -// Licence: GPL - -#include "Tonokip_Firmware.h" -#include "configuration.h" -#include "pins.h" - -#ifdef SDSUPPORT -#include "SdFat.h" -#endif - -// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html -// http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes - -//Implemented Codes -//------------------- -// G0 -> G1 -// G1 - Coordinated Movement X Y Z E -// G4 - Dwell S or P -// G28 - Home all Axis -// G90 - Use Absolute Coordinates -// G91 - Use Relative Coordinates -// G92 - Set current position to cordinates given - -//RepRap M Codes -// M104 - Set extruder target temp -// M105 - Read current temp -// M106 - Fan on -// M107 - Fan off -// M109 - Wait for extruder current temp to reach target temp. -// M114 - Display current position - -//Custom M Codes -// M80 - Turn on Power Supply -// M20 - List SD card -// M21 - Init SD card -// M22 - Release SD card -// M23 - Select SD file (M23 filename.g) -// M24 - Start/resume SD print -// M25 - Pause SD print -// M26 - Set SD position in bytes (M26 S12345) -// M27 - Report SD print status -// M28 - Start SD write (M28 filename.g) -// M29 - Stop SD write -// M81 - Turn off Power Supply -// M82 - Set E codes absolute (default) -// M83 - Set E codes relative while in Absolute Coordinates (G90) mode -// M84 - Disable steppers until next move, -// or use S to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout. -// M85 - Set inactivity shutdown timer with parameter S. To disable set zero (default) -// M92 - Set axis_steps_per_unit - same syntax as G92 -// M115 - Capabilities string -// M140 - Set bed target temp -// M190 - Wait for bed current temp to reach target temp. -// M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000) -// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) - - -//Stepper Movement Variables -char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'}; -bool move_direction[NUM_AXIS]; -const int STEP_PIN[NUM_AXIS] = {X_STEP_PIN, Y_STEP_PIN, Z_STEP_PIN, E_STEP_PIN}; -unsigned long axis_previous_micros[NUM_AXIS]; -unsigned long previous_micros = 0, previous_millis_heater, previous_millis_bed_heater; -unsigned long move_steps_to_take[NUM_AXIS]; -#ifdef RAMP_ACCELERATION - unsigned long axis_max_interval[] = {100000000.0 / (max_start_speed_units_per_second[0] * axis_steps_per_unit[0]), - 100000000.0 / (max_start_speed_units_per_second[1] * axis_steps_per_unit[1]), - 100000000.0 / (max_start_speed_units_per_second[2] * axis_steps_per_unit[2]), - 100000000.0 / (max_start_speed_units_per_second[3] * axis_steps_per_unit[3])}; //TODO: refactor all things like this in a function, or move to setup() - // in a for loop - unsigned long max_interval; - unsigned long axis_steps_per_sqr_second[] = {max_acceleration_units_per_sq_second[0] * axis_steps_per_unit[0], - max_acceleration_units_per_sq_second[1] * axis_steps_per_unit[1], max_acceleration_units_per_sq_second[2] * axis_steps_per_unit[2], - max_acceleration_units_per_sq_second[3] * axis_steps_per_unit[3]}; - unsigned long axis_travel_steps_per_sqr_second[] = {max_travel_acceleration_units_per_sq_second[0] * axis_steps_per_unit[0], - max_travel_acceleration_units_per_sq_second[1] * axis_steps_per_unit[1], max_travel_acceleration_units_per_sq_second[2] * axis_steps_per_unit[2], - max_travel_acceleration_units_per_sq_second[3] * axis_steps_per_unit[3]}; - unsigned long steps_per_sqr_second, plateau_steps; -#endif -boolean acceleration_enabled = false, accelerating = false; -unsigned long interval; -float destination[NUM_AXIS] = {0.0, 0.0, 0.0, 0.0}; -float current_position[NUM_AXIS] = {0.0, 0.0, 0.0, 0.0}; -long axis_interval[NUM_AXIS]; // for speed delay -bool home_all_axis = true; -float feedrate = 1500, next_feedrate, saved_feedrate; -float time_for_move; -long gcode_N, gcode_LastN; -bool relative_mode = false; //Determines Absolute or Relative Coordinates -bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode. -long timediff = 0; -//experimental feedrate calc -float d = 0; -float axis_diff[NUM_AXIS] = {0, 0, 0, 0}; -#ifdef STEP_DELAY_RATIO - long long_step_delay_ratio = STEP_DELAY_RATIO * 100; -#endif - - -// comm variables -#define MAX_CMD_SIZE 96 -#define BUFSIZE 8 -char cmdbuffer[BUFSIZE][MAX_CMD_SIZE]; -bool fromsd[BUFSIZE]; -int bufindr = 0; -int bufindw = 0; -int buflen = 0; -int i = 0; -char serial_char; -int serial_count = 0; -boolean comment_mode = false; -char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc - -// Manage heater variables. For a thermistor or AD595 thermocouple, raw values refer to the -// reading from the analog pin. For a MAX6675 thermocouple, the raw value is the temperature in 0.25 -// degree increments (i.e. 100=25 deg). - -int target_raw = 0; -int current_raw = 0; -int target_bed_raw = 0; -int current_bed_raw = 0; -float tt = 0, bt = 0; -#ifdef PIDTEMP - int temp_iState = 0; - int temp_dState = 0; - int pTerm; - int iTerm; - int dTerm; - //int output; - int error; - int temp_iState_min = 100 * -PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; - int temp_iState_max = 100 * PID_INTEGRAL_DRIVE_MAX / PID_IGAIN; -#endif -#ifdef SMOOTHING - uint32_t nma = SMOOTHFACTOR * analogRead(TEMP_0_PIN); -#endif -#ifdef WATCHPERIOD - int watch_raw = -1000; - unsigned long watchmillis = 0; -#endif -#ifdef MINTEMP - int minttemp = temp2analog(MINTEMP); -#endif -#ifdef MAXTEMP -int maxttemp = temp2analog(MAXTEMP); -#endif - -//Inactivity shutdown variables -unsigned long previous_millis_cmd = 0; -unsigned long max_inactive_time = 0; -unsigned long stepper_inactive_time = 0; - -#ifdef SDSUPPORT - Sd2Card card; - SdVolume volume; - SdFile root; - SdFile file; - uint32_t filesize = 0; - uint32_t sdpos = 0; - bool sdmode = false; - bool sdactive = false; - bool savetosd = false; - int16_t n; - - void initsd(){ - sdactive = false; - #if SDSS >- 1 - if(root.isOpen()) - root.close(); - if (!card.init(SPI_FULL_SPEED,SDSS)){ - //if (!card.init(SPI_HALF_SPEED,SDSS)) - Serial.println("SD init fail"); - } - else if (!volume.init(&card)) - Serial.println("volume.init failed"); - else if (!root.openRoot(&volume)) - Serial.println("openRoot failed"); - else - sdactive = true; - #endif - } - - inline void 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'; - //Serial.println(begin); - file.write(begin); - if (file.writeError){ - Serial.println("error writing to file"); - } - } -#endif - - -void setup() -{ - Serial.begin(BAUDRATE); - Serial.println("start"); - for(int i = 0; i < BUFSIZE; i++){ - fromsd[i] = false; - } - - //Initialize Step Pins - for(int i=0; i < NUM_AXIS; i++) if(STEP_PIN[i] > -1) pinMode(STEP_PIN[i],OUTPUT); - - //Initialize Dir Pins - if(X_DIR_PIN > -1) pinMode(X_DIR_PIN,OUTPUT); - if(Y_DIR_PIN > -1) pinMode(Y_DIR_PIN,OUTPUT); - if(Z_DIR_PIN > -1) pinMode(Z_DIR_PIN,OUTPUT); - if(E_DIR_PIN > -1) pinMode(E_DIR_PIN,OUTPUT); - - //Steppers default to disabled. - if(X_ENABLE_PIN > -1) if(!X_ENABLE_ON) digitalWrite(X_ENABLE_PIN,HIGH); - if(Y_ENABLE_PIN > -1) if(!Y_ENABLE_ON) digitalWrite(Y_ENABLE_PIN,HIGH); - if(Z_ENABLE_PIN > -1) if(!Z_ENABLE_ON) digitalWrite(Z_ENABLE_PIN,HIGH); - if(E_ENABLE_PIN > -1) if(!E_ENABLE_ON) digitalWrite(E_ENABLE_PIN,HIGH); - - //endstop pullups - #ifdef ENDSTOPPULLUPS - if(X_MIN_PIN > -1) { pinMode(X_MIN_PIN,INPUT); digitalWrite(X_MIN_PIN,HIGH);} - if(Y_MIN_PIN > -1) { pinMode(Y_MIN_PIN,INPUT); digitalWrite(Y_MIN_PIN,HIGH);} - if(Z_MIN_PIN > -1) { pinMode(Z_MIN_PIN,INPUT); digitalWrite(Z_MIN_PIN,HIGH);} - if(X_MAX_PIN > -1) { pinMode(X_MAX_PIN,INPUT); digitalWrite(X_MAX_PIN,HIGH);} - if(Y_MAX_PIN > -1) { pinMode(Y_MAX_PIN,INPUT); digitalWrite(Y_MAX_PIN,HIGH);} - if(Z_MAX_PIN > -1) { pinMode(Z_MAX_PIN,INPUT); digitalWrite(Z_MAX_PIN,HIGH);} - #endif - //Initialize Enable Pins - if(X_ENABLE_PIN > -1) pinMode(X_ENABLE_PIN,OUTPUT); - if(Y_ENABLE_PIN > -1) pinMode(Y_ENABLE_PIN,OUTPUT); - if(Z_ENABLE_PIN > -1) pinMode(Z_ENABLE_PIN,OUTPUT); - if(E_ENABLE_PIN > -1) pinMode(E_ENABLE_PIN,OUTPUT); - - if(HEATER_0_PIN > -1) pinMode(HEATER_0_PIN,OUTPUT); - if(HEATER_1_PIN > -1) pinMode(HEATER_1_PIN,OUTPUT); - -#ifdef HEATER_USES_MAX6675 - digitalWrite(SCK_PIN,0); - pinMode(SCK_PIN,OUTPUT); - - digitalWrite(MOSI_PIN,1); - pinMode(MOSI_PIN,OUTPUT); - - digitalWrite(MISO_PIN,1); - pinMode(MISO_PIN,INPUT); - - digitalWrite(MAX6675_SS,1); - pinMode(MAX6675_SS,OUTPUT); -#endif - -#ifdef SDSUPPORT - - //power to SD reader - #if SDPOWER > -1 - pinMode(SDPOWER,OUTPUT); - digitalWrite(SDPOWER,HIGH); - #endif - initsd(); - -#endif - -} - - -void loop() -{ - if(buflen<3) - get_command(); - - if(buflen){ -#ifdef SDSUPPORT - if(savetosd){ - if(strstr(cmdbuffer[bufindr],"M29") == NULL){ - write_command(cmdbuffer[bufindr]); - Serial.println("ok"); - }else{ - file.sync(); - file.close(); - savetosd = false; - Serial.println("Done saving file."); - } - }else{ - process_commands(); - } -#else - process_commands(); -#endif - buflen = (buflen-1); - bufindr = (bufindr + 1)%BUFSIZE; - } - //check heater every n milliseconds - manage_heater(); - manage_inactivity(1); - } - - -inline void get_command() -{ - while( Serial.available() > 0 && buflen < BUFSIZE) { - serial_char = Serial.read(); - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = false; - if(strstr(cmdbuffer[bufindw], "N") != NULL) - { - strchr_pointer = strchr(cmdbuffer[bufindw], 'N'); - gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) { - Serial.print("Serial Error: Line Number is not Last Line Number+1, Last Line:"); - Serial.println(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if(strstr(cmdbuffer[bufindw], "*") != NULL) - { - byte checksum = 0; - byte count = 0; - while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++]; - strchr_pointer = strchr(cmdbuffer[bufindw], '*'); - - if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) { - Serial.print("Error: checksum mismatch, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - //if no errors, continue parsing - } - else - { - Serial.print("Error: No Checksum with line number, Last Line:"); - Serial.println(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - gcode_LastN = gcode_N; - //if no errors, continue parsing - } - else // if we don't receive 'N' but still see '*' - { - if((strstr(cmdbuffer[bufindw], "*") != NULL)) - { - Serial.print("Error: No Line Number with checksum, Last Line:"); - Serial.println(gcode_LastN); - serial_count = 0; - return; - } - } - if((strstr(cmdbuffer[bufindw], "G") != NULL)){ - strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); - switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){ - case 0: - case 1: - #ifdef SDSUPPORT - if(savetosd) - break; - #endif - Serial.println("ok"); - break; - default: - break; - } - - } - bufindw = (bufindw + 1)%BUFSIZE; - buflen += 1; - - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } - } -#ifdef SDSUPPORT -if(!sdmode || serial_count!=0){ - return; -} - while( filesize > sdpos && buflen < BUFSIZE) { - n = file.read(); - serial_char = (char)n; - if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1) || n == -1) - { - sdpos = file.curPosition(); - if(sdpos >= filesize){ - sdmode = false; - Serial.println("Done printing file"); - } - if(!serial_count) return; //if empty line - cmdbuffer[bufindw][serial_count] = 0; //terminate string - if(!comment_mode){ - fromsd[bufindw] = true; - buflen += 1; - bufindw = (bufindw + 1)%BUFSIZE; - } - comment_mode = false; //for new command - serial_count = 0; //clear buffer - } - else - { - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; - } -} -#endif - -} - - -inline float code_value() { return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); } -inline long code_value_long() { return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); } -inline bool code_seen(char code_string[]) { return (strstr(cmdbuffer[bufindr], code_string) != NULL); } //Return True if the string was found - -inline bool code_seen(char code) -{ - strchr_pointer = strchr(cmdbuffer[bufindr], code); - return (strchr_pointer != NULL); //Return True if a character was found -} - -inline void process_commands() -{ - unsigned long codenum; //throw away variable - char *starpos = NULL; - - if(code_seen('G')) - { - switch((int)code_value()) - { - case 0: // G0 -> G1 - case 1: // G1 - #ifdef DISABLE_CHECK_DURING_ACC || DISABLE_CHECK_DURING_MOVE || DISABLE_CHECK_DURING_TRAVEL - manage_heater(); - #endif - get_coordinates(); // For X Y Z E F - prepare_move(); - previous_millis_cmd = millis(); - //ClearToSend(); - return; - //break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - codenum += millis(); // keep track of when we started waiting - while(millis() < codenum ){ - manage_heater(); - } - break; - case 28: //G28 Home all Axis one at a time - saved_feedrate = feedrate; - for(int i=0; i < NUM_AXIS; i++) { - destination[i] = 0; - current_position[i] = 0; - } - feedrate = 0; - - home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))); - - if((home_all_axis) || (code_seen('X'))) { - if((X_MIN_PIN > -1 && X_HOME_DIR==-1) || (X_MAX_PIN > -1 && X_HOME_DIR==1)) { - current_position[0] = 0; - destination[0] = 1.5 * X_MAX_LENGTH * X_HOME_DIR; - feedrate = max_start_speed_units_per_second[0] * 60; - prepare_move(); - - current_position[0] = 0; - destination[0] = -1 * X_HOME_DIR; - prepare_move(); - - destination[0] = 10 * X_HOME_DIR; - prepare_move(); - - current_position[0] = 0; - destination[0] = 0; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen('X'))) { - if((Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (Y_MAX_PIN > -1 && Y_HOME_DIR==1)) { - current_position[1] = 0; - destination[1] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; - feedrate = max_start_speed_units_per_second[1] * 60; - prepare_move(); - - current_position[1] = 0; - destination[1] = -1 * Y_HOME_DIR; - prepare_move(); - - destination[1] = 10 * Y_HOME_DIR; - prepare_move(); - - current_position[1] = 0; - destination[1] = 0; - feedrate = 0; - } - } - - if((home_all_axis) || (code_seen('X'))) { - if((Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (Z_MAX_PIN > -1 && Z_HOME_DIR==1)) { - current_position[2] = 0; - destination[2] = 1.5 * Z_MAX_LENGTH * Z_HOME_DIR; - feedrate = max_feedrate[2]/2; - prepare_move(); - - current_position[2] = 0; - destination[2] = -1 * Z_HOME_DIR; - prepare_move(); - - destination[2] = 10 * Z_HOME_DIR; - prepare_move(); - - current_position[2] = 0; - destination[2] = 0; - feedrate = 0; - } - } - - feedrate = saved_feedrate; - previous_millis_cmd = millis(); - break; - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) current_position[i] = code_value(); - } - break; - - } - } - - else if(code_seen('M')) - { - - switch( (int)code_value() ) - { -#ifdef SDSUPPORT - - case 20: // M20 - list SD card - Serial.println("Begin file list"); - root.ls(); - Serial.println("End file list"); - break; - case 21: // M21 - init SD card - sdmode = false; - initsd(); - break; - case 22: //M22 - release SD card - sdmode = false; - sdactive = false; - break; - case 23: //M23 - Select file - if(sdactive){ - sdmode = false; - file.close(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos-1)='\0'; - if (file.open(&root, strchr_pointer + 4, O_READ)) { - Serial.print("File opened:"); - Serial.print(strchr_pointer + 4); - Serial.print(" Size:"); - Serial.println(file.fileSize()); - sdpos = 0; - filesize = file.fileSize(); - Serial.println("File selected"); - } - else{ - Serial.println("file.open failed"); - } - } - break; - case 24: //M24 - Start SD print - if(sdactive){ - sdmode = true; - } - break; - case 25: //M25 - Pause SD print - if(sdmode){ - sdmode = false; - } - break; - case 26: //M26 - Set SD index - if(sdactive && code_seen('S')){ - sdpos = code_value_long(); - file.seekSet(sdpos); - } - break; - case 27: //M27 - Get SD status - if(sdactive){ - Serial.print("SD printing byte "); - Serial.print(sdpos); - Serial.print("/"); - Serial.println(filesize); - }else{ - Serial.println("Not SD printing"); - } - break; - case 28: //M28 - Start SD write - if(sdactive){ - char* npos = 0; - file.close(); - sdmode = false; - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - npos = strchr(cmdbuffer[bufindr], 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos-1) = '\0'; - } - if (!file.open(&root, strchr_pointer+4, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) - { - Serial.print("open failed, File: "); - Serial.print(strchr_pointer + 4); - Serial.print("."); - }else{ - savetosd = true; - Serial.print("Writing to file: "); - Serial.println(strchr_pointer + 4); - } - } - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //savetosd = false; - break; -#endif - case 104: // M104 - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw > current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - break; - case 140: // M140 set bed temp - if (code_seen('S')) target_bed_raw = temp2analogBed(code_value()); - break; - case 105: // M105 - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) - tt = analog2temp(current_raw); - #endif - #if TEMP_1_PIN > -1 - bt = analog2tempBed(current_bed_raw); - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX6675) - Serial.print("ok T:"); - Serial.print(tt); - #if TEMP_1_PIN > -1 - Serial.print(" B:"); - Serial.println(bt); - #else - Serial.println(); - #endif - #else - Serial.println("No thermistors - no temp"); - #endif - return; - //break; - case 109: // M109 - Wait for extruder heater to reach target. - if (code_seen('S')) target_raw = temp2analog(code_value()); - #ifdef WATCHPERIOD - if(target_raw>current_raw){ - watchmillis = max(1,millis()); - watch_raw = current_raw; - }else{ - watchmillis = 0; - } - #endif - codenum = millis(); - while(current_raw < target_raw) { - if( (millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - Serial.print("T:"); - Serial.println( analog2temp(current_raw) ); - codenum = millis(); - } - manage_heater(); - } - break; - case 190: // M190 - Wait bed for heater to reach target. - #if TEMP_1_PIN > -1 - if (code_seen('S')) target_bed_raw = temp2analog(code_value()); - codenum = millis(); - while(current_bed_raw < target_bed_raw) { - if( (millis()-codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - tt=analog2temp(current_raw); - Serial.print("T:"); - Serial.println( tt ); - Serial.print("ok T:"); - Serial.print( tt ); - Serial.print(" B:"); - Serial.println( analog2temp(current_bed_raw) ); - codenum = millis(); - } - manage_heater(); - } - #endif - break; - case 106: //M106 Fan On - if (code_seen('S')){ - digitalWrite(FAN_PIN, HIGH); - analogWrite(FAN_PIN, constrain(code_value(),0,255) ); - } - else - digitalWrite(FAN_PIN, HIGH); - break; - case 107: //M107 Fan Off - analogWrite(FAN_PIN, 0); - - digitalWrite(FAN_PIN, LOW); - break; - case 80: // M81 - ATX Power On - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,OUTPUT); //GND - break; - case 81: // M81 - ATX Power Off - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); //Floating - break; - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 84: - if(code_seen('S')){ stepper_inactive_time = code_value() * 1000; } - else{ disable_x(); disable_y(); disable_z(); disable_e(); } - break; - case 85: // M85 - code_seen('S'); - max_inactive_time = code_value() * 1000; - break; - case 92: // M92 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_unit[i] = code_value(); - } - - //Update start speed intervals and axis order. TODO: refactor axis_max_interval[] calculation into a function, as it - // should also be used in setup() as well - #ifdef RAMP_ACCELERATION - long temp_max_intervals[NUM_AXIS]; - for(int i=0; i < NUM_AXIS; i++) { - axis_max_interval[i] = 100000000.0 / (max_start_speed_units_per_second[i] * axis_steps_per_unit[i]);//TODO: do this for - // all steps_per_unit related variables - } - #endif - break; - case 115: // M115 - Serial.println("FIRMWARE_NAME:Sprinter FIRMWARE_URL:http%%3A/github.com/kliment/Sprinter/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1"); - break; - case 114: // M114 - Serial.print("X:"); - Serial.print(current_position[0]); - Serial.print("Y:"); - Serial.print(current_position[1]); - Serial.print("Z:"); - Serial.print(current_position[2]); - Serial.print("E:"); - Serial.println(current_position[3]); - break; - #ifdef RAMP_ACCELERATION - //TODO: update for all axis, use for loop - case 201: // M201 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; - case 202: // M202 - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i]; - } - break; - #endif - } - - } - else{ - Serial.println("Unknown command:"); - Serial.println(cmdbuffer[bufindr]); - } - - ClearToSend(); - -} - -inline void FlushSerialRequestResend() -{ - //char cmdbuffer[bufindr][100]="Resend:"; - Serial.flush(); - Serial.print("Resend:"); - Serial.println(gcode_LastN + 1); - ClearToSend(); -} - -inline void ClearToSend() -{ - previous_millis_cmd = millis(); - #ifdef SDSUPPORT - if(fromsd[bufindr]) - return; - #endif - Serial.println("ok"); -} - -inline void get_coordinates() -{ - for(int i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i]; - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); - if(next_feedrate > 0.0) feedrate = next_feedrate; - } -} - -inline void prepare_move() -{ - //Find direction - for(int i=0; i < NUM_AXIS; i++) { - if(destination[i] >= current_position[i]) move_direction[i] = 1; - else move_direction[i] = 0; - } - - - if (min_software_endstops) { - if (destination[0] < 0) destination[0] = 0.0; - if (destination[1] < 0) destination[1] = 0.0; - if (destination[2] < 0) destination[2] = 0.0; - } - - if (max_software_endstops) { - if (destination[0] > X_MAX_LENGTH) destination[0] = X_MAX_LENGTH; - if (destination[1] > Y_MAX_LENGTH) destination[1] = Y_MAX_LENGTH; - if (destination[2] > Z_MAX_LENGTH) destination[2] = Z_MAX_LENGTH; - } - - for(int i=0; i < NUM_AXIS; i++) { - axis_diff[i] = destination[i] - current_position[i]; - move_steps_to_take[i] = abs(axis_diff[i]) * axis_steps_per_unit[i]; - } - if(feedrate < 10) - feedrate = 10; - - //Feedrate calc based on XYZ travel distance - float xy_d; - if(abs(axis_diff[0]) > 0 || abs(axis_diff[1]) > 0 || abs(axis_diff[2])) { - xy_d = sqrt(axis_diff[0] * axis_diff[0] + axis_diff[1] * axis_diff[1]); - d = sqrt(xy_d * xy_d + axis_diff[2] * axis_diff[2]); - } - else if(abs(axis_diff[3]) > 0) - d = abs(axis_diff[3]); - #ifdef DEBUG_PREPARE_MOVE - else { - log_message("_PREPARE_MOVE - No steps to take!"); - } - #endif - time_for_move = (d / (feedrate / 60000000.0) ); - //Check max feedrate for each axis is not violated, update time_for_move if necessary - for(int i = 0; i < NUM_AXIS; i++) { - if(move_steps_to_take[i] && abs(axis_diff[i]) / (time_for_move / 60000000.0) > max_feedrate[i]) { - time_for_move = time_for_move / max_feedrate[i] * (abs(axis_diff[i]) / (time_for_move / 60000000.0)); - } - } - //Calculate the full speed stepper interval for each axis - for(int i=0; i < NUM_AXIS; i++) { - if(move_steps_to_take[i]) axis_interval[i] = time_for_move / move_steps_to_take[i] * 100; - } - - #ifdef DEBUG_PREPARE_MOVE - log_float("_PREPARE_MOVE - Move distance on the XY plane", xy_d); - log_float("_PREPARE_MOVE - Move distance on the XYZ space", d); - log_float("_PREPARE_MOVE - Commanded feedrate", feedrate); - log_float("_PREPARE_MOVE - Constant full speed move time", time_for_move); - log_float_array("_PREPARE_MOVE - Destination", destination, NUM_AXIS); - log_float_array("_PREPARE_MOVE - Current position", current_position, NUM_AXIS); - log_ulong_array("_PREPARE_MOVE - Steps to take", move_steps_to_take, NUM_AXIS); - log_long_array("_PREPARE_MOVE - Axes full speed intervals", axis_interval, NUM_AXIS); - #endif - - unsigned long move_steps[NUM_AXIS]; - for(int i=0; i < NUM_AXIS; i++) - move_steps[i] = move_steps_to_take[i]; - linear_move(move_steps); // make the move -} - -void linear_move(unsigned long axis_steps_remaining[]) // make linear move with preset speeds and destinations, see G0 and G1 -{ - //Determine direction of movement - if (destination[0] > current_position[0]) digitalWrite(X_DIR_PIN,!INVERT_X_DIR); - else digitalWrite(X_DIR_PIN,INVERT_X_DIR); - if (destination[1] > current_position[1]) digitalWrite(Y_DIR_PIN,!INVERT_Y_DIR); - else digitalWrite(Y_DIR_PIN,INVERT_Y_DIR); - if (destination[2] > current_position[2]) digitalWrite(Z_DIR_PIN,!INVERT_Z_DIR); - else digitalWrite(Z_DIR_PIN,INVERT_Z_DIR); - if (destination[3] > current_position[3]) digitalWrite(E_DIR_PIN,!INVERT_E_DIR); - else digitalWrite(E_DIR_PIN,INVERT_E_DIR); - - if(X_MIN_PIN > -1) if(!move_direction[0]) if(digitalRead(X_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[0]=0; - if(Y_MIN_PIN > -1) if(!move_direction[1]) if(digitalRead(Y_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[1]=0; - if(Z_MIN_PIN > -1) if(!move_direction[2]) if(digitalRead(Z_MIN_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[2]=0; - if(X_MAX_PIN > -1) if(move_direction[0]) if(digitalRead(X_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[0]=0; - if(Y_MAX_PIN > -1) if(move_direction[1]) if(digitalRead(Y_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[1]=0; - if(Z_MAX_PIN > -1) if(move_direction[2]) if(digitalRead(Z_MAX_PIN) != ENDSTOPS_INVERTING) axis_steps_remaining[2]=0; - - - //Only enable axis that are moving. If the axis doesn't need to move then it can stay disabled depending on configuration. - // TODO: maybe it's better to refactor into a generic enable(int axis) function, that will probably take more ram, - // but will reduce code size - if(axis_steps_remaining[0]) enable_x(); - if(axis_steps_remaining[1]) enable_y(); - if(axis_steps_remaining[2]) enable_z(); - if(axis_steps_remaining[3]) enable_e(); - - //Define variables that are needed for the Bresenham algorithm. Please note that Z is not currently included in the Bresenham algorithm. - unsigned long delta[] = {axis_steps_remaining[0], axis_steps_remaining[1], axis_steps_remaining[2], axis_steps_remaining[3]}; //TODO: implement a "for" to support N axes - long axis_error[NUM_AXIS]; - unsigned int primary_axis; - if(delta[1] > delta[0] && delta[1] > delta[2] && delta[1] > delta[3]) primary_axis = 1; - else if (delta[0] >= delta[1] && delta[0] > delta[2] && delta[0] > delta[3]) primary_axis = 0; - else if (delta[2] >= delta[0] && delta[2] >= delta[1] && delta[2] > delta[3]) primary_axis = 2; - else primary_axis = 3; - unsigned long steps_remaining = delta[primary_axis]; - unsigned long steps_to_take = steps_remaining; - for(int i=0; i < NUM_AXIS; i++) if(i != primary_axis) axis_error[i] = delta[primary_axis] / 2; - interval = axis_interval[primary_axis]; - bool is_print_move = delta[3] > 0; - #ifdef DEBUG_BRESENHAM - log_int("_BRESENHAM - Primary axis", primary_axis); - log_int("_BRESENHAM - Primary axis full speed interval", interval); - log_ulong_array("_BRESENHAM - Deltas", delta, NUM_AXIS); - log_long_array("_BRESENHAM - Errors", axis_error, NUM_AXIS); - #endif - - //If acceleration is enabled, do some Bresenham calculations depending on which axis will lead it. - #ifdef RAMP_ACCELERATION - long max_speed_steps_per_second; - long min_speed_steps_per_second; - max_interval = axis_max_interval[primary_axis]; - #ifdef DEBUG_RAMP_ACCELERATION - log_ulong_array("_RAMP_ACCELERATION - Teoric step intervals at move start", axis_max_interval, NUM_AXIS); - #endif - unsigned long new_axis_max_intervals[NUM_AXIS]; - max_speed_steps_per_second = 100000000 / interval; - min_speed_steps_per_second = 100000000 / max_interval; //TODO: can this be deleted? - //Calculate start speeds based on moving axes max start speed constraints. - int slowest_start_axis = primary_axis; - unsigned long slowest_start_axis_max_interval = max_interval; - for(int i = 0; i < NUM_AXIS; i++) - if (axis_steps_remaining[i] >0 && i != primary_axis && axis_max_interval[i] * axis_steps_remaining[i] - / axis_steps_remaining[slowest_start_axis] > slowest_start_axis_max_interval) { - slowest_start_axis = i; - slowest_start_axis_max_interval = axis_max_interval[i]; - } - for(int i = 0; i < NUM_AXIS; i++) - if(axis_steps_remaining[i] >0) { - new_axis_max_intervals[i] = slowest_start_axis_max_interval * axis_steps_remaining[slowest_start_axis] / axis_steps_remaining[i]; - if(i == primary_axis) { - max_interval = new_axis_max_intervals[i]; - min_speed_steps_per_second = 100000000 / max_interval; - } - } - //Calculate slowest axis plateau time - float slowest_axis_plateau_time = 0; - for(int i=0; i < NUM_AXIS ; i++) { - if(axis_steps_remaining[i] > 0) { - if(is_print_move && axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, - (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_steps_per_sqr_second[i]); - else if(axis_steps_remaining[i] > 0) slowest_axis_plateau_time = max(slowest_axis_plateau_time, - (100000000.0 / axis_interval[i] - 100000000.0 / new_axis_max_intervals[i]) / (float) axis_travel_steps_per_sqr_second[i]); - } - } - //Now we can calculate the new primary axis acceleration, so that the slowest axis max acceleration is not violated - steps_per_sqr_second = (100000000.0 / axis_interval[primary_axis] - 100000000.0 / new_axis_max_intervals[primary_axis]) / slowest_axis_plateau_time; - plateau_steps = (long) ((steps_per_sqr_second / 2.0 * slowest_axis_plateau_time + min_speed_steps_per_second) * slowest_axis_plateau_time); - #ifdef DEBUG_RAMP_ACCELERATION - log_int("_RAMP_ACCELERATION - Start speed limiting axis", slowest_start_axis); - log_ulong("_RAMP_ACCELERATION - Limiting axis start interval", slowest_start_axis_max_interval); - log_ulong_array("_RAMP_ACCELERATION - Actual step intervals at move start", new_axis_max_intervals, NUM_AXIS); - #endif - #endif - - unsigned long steps_done = 0; - #ifdef RAMP_ACCELERATION - plateau_steps *= 1.01; // This is to compensate we use discrete intervals - acceleration_enabled = true; - long full_interval = interval; - if(interval > max_interval) acceleration_enabled = false; - boolean decelerating = false; - #endif - - unsigned long start_move_micros = micros(); - for(int i = 0; i < NUM_AXIS; i++) { - axis_previous_micros[i] = start_move_micros * 100; - } - - #ifdef DISABLE_CHECK_DURING_TRAVEL - //If the move time is more than allowed in DISABLE_CHECK_DURING_TRAVEL, let's - // consider this a print move and perform heat management during it - if(time_for_move / 1000 > DISABLE_CHECK_DURING_TRAVEL) is_print_move = true; - //else, if the move is a retract, consider it as a travel move for the sake of this feature - else if(delta[3]>0 && delta[0] + delta[1] + delta[2] == 0) is_print_move = false; - #ifdef DEBUG_DISABLE_CHECK_DURING_TRAVEL - log_bool("_DISABLE_CHECK_DURING_TRAVEL - is_print_move", is_print_move); - #endif - #endif - - #ifdef DEBUG_MOVE_TIME - unsigned long startmove = micros(); - #endif - - //move until no more steps remain - while(axis_steps_remaining[0] + axis_steps_remaining[1] + axis_steps_remaining[2] + axis_steps_remaining[3] > 0) { - #ifdef DISABLE_CHECK_DURING_ACC - if(!accelerating && !decelerating) { - //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp - #ifdef DISABLE_CHECK_DURING_TRAVEL - if(is_print_move) - #endif - manage_heater(); - } - #else - #ifdef DISABLE_CHECK_DURING_MOVE - {} //Do nothing - #else - //If more that HEATER_CHECK_INTERVAL ms have passed since previous heating check, adjust temp - #ifdef DISABLE_CHECK_DURING_TRAVEL - if(is_print_move) - #endif - manage_heater(); - #endif - #endif - #ifdef RAMP_ACCELERATION - //If acceleration is enabled on this move and we are in the acceleration segment, calculate the current interval - if (acceleration_enabled && steps_done == 0) { - interval = max_interval; - } else if (acceleration_enabled && steps_done <= plateau_steps) { - long current_speed = (long) ((((long) steps_per_sqr_second) / 10000) - * ((micros() - start_move_micros) / 100) + (long) min_speed_steps_per_second); - interval = 100000000 / current_speed; - if (interval < full_interval) { - accelerating = false; - interval = full_interval; - } - if (steps_done >= steps_to_take / 2) { - plateau_steps = steps_done; - max_speed_steps_per_second = 100000000 / interval; - accelerating = false; - } - } else if (acceleration_enabled && steps_remaining <= plateau_steps) { //(interval > minInterval * 100) { - if (!accelerating) { - start_move_micros = micros(); - accelerating = true; - decelerating = true; - } - long current_speed = (long) ((long) max_speed_steps_per_second - ((((long) steps_per_sqr_second) / 10000) - * ((micros() - start_move_micros) / 100))); - interval = 100000000 / current_speed; - if (interval > max_interval) - interval = max_interval; - } else { - //Else, we are just use the full speed interval as current interval - interval = full_interval; - accelerating = false; - } - #endif - - //If there are x or y steps remaining, perform Bresenham algorithm - if(axis_steps_remaining[primary_axis]) { - if(X_MIN_PIN > -1) if(!move_direction[0]) if(digitalRead(X_MIN_PIN) != ENDSTOPS_INVERTING) break; - if(Y_MIN_PIN > -1) if(!move_direction[1]) if(digitalRead(Y_MIN_PIN) != ENDSTOPS_INVERTING) break; - if(X_MAX_PIN > -1) if(move_direction[0]) if(digitalRead(X_MAX_PIN) != ENDSTOPS_INVERTING) break; - if(Y_MAX_PIN > -1) if(move_direction[1]) if(digitalRead(Y_MAX_PIN) != ENDSTOPS_INVERTING) break; - if(Z_MIN_PIN > -1) if(!move_direction[2]) if(digitalRead(Z_MIN_PIN) != ENDSTOPS_INVERTING) break; - if(Z_MAX_PIN > -1) if(move_direction[2]) if(digitalRead(Z_MAX_PIN) != ENDSTOPS_INVERTING) break; - timediff = micros() * 100 - axis_previous_micros[primary_axis]; - while(timediff >= interval && axis_steps_remaining[primary_axis] > 0) { - steps_done++; - steps_remaining--; - axis_steps_remaining[primary_axis]--; timediff -= interval; - do_step_update_micros(primary_axis); - for(int i=0; i < NUM_AXIS; i++) if(i != primary_axis && axis_steps_remaining[i] > 0) { - axis_error[i] = axis_error[i] - delta[i]; - if(axis_error[i] < 0) { - do_step(i); axis_steps_remaining[i]--; - axis_error[i] = axis_error[i] + delta[primary_axis]; - } - } - #ifdef STEP_DELAY_RATIO - if(timediff >= interval) delayMicroseconds(long_step_delay_ratio * interval / 10000); - #endif - #ifdef STEP_DELAY_MICROS - if(timediff >= interval) delayMicroseconds(STEP_DELAY_MICROS); - #endif - } - } - } - #ifdef DEBUG_MOVE_TIME - log_ulong("_MOVE_TIME - This move took", micros()-startmove); - #endif - - if(DISABLE_X) disable_x(); - if(DISABLE_Y) disable_y(); - if(DISABLE_Z) disable_z(); - if(DISABLE_E) disable_e(); - - // Update current position partly based on direction, we probably can combine this with the direction code above... - for(int i=0; i < NUM_AXIS; i++) { - if (destination[i] > current_position[i]) current_position[i] = current_position[i] + move_steps_to_take[i] / axis_steps_per_unit[i]; - else current_position[i] = current_position[i] - move_steps_to_take[i] / axis_steps_per_unit[i]; - } -} - -inline void do_step_update_micros(int axis) { - digitalWrite(STEP_PIN[axis], HIGH); - axis_previous_micros[axis] += interval; - digitalWrite(STEP_PIN[axis], LOW); -} - -inline void do_step(int axis) { - digitalWrite(STEP_PIN[axis], HIGH); - digitalWrite(STEP_PIN[axis], LOW); -} - -inline void disable_x() { if(X_ENABLE_PIN > -1) digitalWrite(X_ENABLE_PIN,!X_ENABLE_ON); } -inline void disable_y() { if(Y_ENABLE_PIN > -1) digitalWrite(Y_ENABLE_PIN,!Y_ENABLE_ON); } -inline void disable_z() { if(Z_ENABLE_PIN > -1) digitalWrite(Z_ENABLE_PIN,!Z_ENABLE_ON); } -inline void disable_e() { if(E_ENABLE_PIN > -1) digitalWrite(E_ENABLE_PIN,!E_ENABLE_ON); } -inline void enable_x() { if(X_ENABLE_PIN > -1) digitalWrite(X_ENABLE_PIN, X_ENABLE_ON); } -inline void enable_y() { if(Y_ENABLE_PIN > -1) digitalWrite(Y_ENABLE_PIN, Y_ENABLE_ON); } -inline void enable_z() { if(Z_ENABLE_PIN > -1) digitalWrite(Z_ENABLE_PIN, Z_ENABLE_ON); } -inline void enable_e() { if(E_ENABLE_PIN > -1) digitalWrite(E_ENABLE_PIN, E_ENABLE_ON); } - -#define HEAT_INTERVAL 250 -#ifdef HEATER_USES_MAX6675 -unsigned long max6675_previous_millis = 0; -int max6675_temp = 2000; - -inline int read_max6675() -{ - if (millis() - max6675_previous_millis < HEAT_INTERVAL) - return max6675_temp; - - max6675_previous_millis = millis(); - - max6675_temp = 0; - - #ifdef PRR - PRR &= ~(1<> 3; - } - - return max6675_temp; -} -#endif - - -inline void manage_heater() -{ - if((millis() - previous_millis_heater) < HEATER_CHECK_INTERVAL ) - return; - previous_millis_heater = millis(); - #ifdef HEATER_USES_THERMISTOR - current_raw = analogRead(TEMP_0_PIN); - #ifdef DEBUG_HEAT_MGMT - log_int("_HEAT_MGMT - analogRead(TEMP_0_PIN)", current_raw); - log_int("_HEAT_MGMT - NUMTEMPS", NUMTEMPS); - #endif - // When using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_raw = 1023 - current_raw; - #elif defined HEATER_USES_AD595 - current_raw = analogRead(TEMP_0_PIN); - #elif defined HEATER_USES_MAX6675 - current_raw = read_max6675(); - #endif - #ifdef SMOOTHING - nma = (nma + current_raw) - (nma / SMOOTHFACTOR); - current_raw = nma / SMOOTHFACTOR; - #endif - #ifdef WATCHPERIOD - if(watchmillis && millis() - watchmillis > WATCHPERIOD){ - if(watch_raw + 1 >= current_raw){ - target_raw = 0; - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - }else{ - watchmillis = 0; - } - } - #endif - #ifdef MINTEMP - if(current_raw <= minttemp) - target_raw = 0; - #endif - #ifdef MAXTEMP - if(current_raw >= maxttemp) { - target_raw = 0; - } - #endif - #if (TEMP_0_PIN > -1) || defined (HEATER_USES_MAX66675) - #ifdef PIDTEMP - error = target_raw - current_raw; - pTerm = (PID_PGAIN * error) / 100; - temp_iState += error; - temp_iState = constrain(temp_iState, temp_iState_min, temp_iState_max); - iTerm = (PID_IGAIN * temp_iState) / 100; - dTerm = (PID_DGAIN * (current_raw - temp_dState)) / 100; - temp_dState = current_raw; - analogWrite(HEATER_0_PIN, constrain(pTerm + iTerm - dTerm, 0, PID_MAX)); - #else - if(current_raw >= target_raw) - { - digitalWrite(HEATER_0_PIN,LOW); - digitalWrite(LED_PIN,LOW); - } - else - { - digitalWrite(HEATER_0_PIN,HIGH); - digitalWrite(LED_PIN,HIGH); - } - #endif - #endif - - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - - #ifdef BED_USES_THERMISTOR - - current_bed_raw = analogRead(TEMP_1_PIN); - #ifdef DEBUG_HEAT_MGMT - log_int("_HEAT_MGMT - analogRead(TEMP_1_PIN)", current_bed_raw); - log_int("_HEAT_MGMT - BNUMTEMPS", BNUMTEMPS); - #endif - - // If using thermistor, when the heater is colder than targer temp, we get a higher analog reading than target, - // this switches it up so that the reading appears lower than target for the control logic. - current_bed_raw = 1023 - current_bed_raw; - #elif defined BED_USES_AD595 - current_bed_raw = analogRead(TEMP_1_PIN); - - #endif - - - #if TEMP_1_PIN > -1 - if(current_bed_raw >= target_bed_raw) - { - digitalWrite(HEATER_1_PIN,LOW); - } - else - { - digitalWrite(HEATER_1_PIN,HIGH); - } - #endif -} - -// Takes hot end temperature value as input and returns corresponding raw value. -// For a thermistor, it uses the RepRap thermistor temp table. -// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value. -// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware. -float temp2analog(int celsius) { - #ifdef HEATER_USES_THERMISTOR - int raw = 0; - byte i; - - for (i=1; i raw) - { - celsius = temptable[i-1][1] + - (raw - temptable[i-1][0]) * - (temptable[i][1] - temptable[i-1][1]) / - (temptable[i][0] - temptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = temptable[i-1][1]; - - return celsius; - #elif defined HEATER_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #elif defined HEATER_USES_MAX6675 - return raw * 0.25; - #endif -} - -// Derived from RepRap FiveD extruder::getTemperature() -// For bed temperature measurement. -float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR - int celsius = 0; - byte i; - - raw = 1023 - raw; - - for (i=1; i raw) - { - celsius = bedtemptable[i-1][1] + - (raw - bedtemptable[i-1][0]) * - (bedtemptable[i][1] - bedtemptable[i-1][1]) / - (bedtemptable[i][0] - bedtemptable[i-1][0]); - - break; - } - } - - // Overflow: Set to last value in the table - if (i == NUMTEMPS) celsius = bedtemptable[i-1][1]; - - return celsius; - - #elif defined BED_USES_AD595 - return raw * ((5.0 * 100.0) / 1024.0); - #endif -} - -inline void kill() -{ - #if TEMP_0_PIN > -1 - target_raw=0; - digitalWrite(HEATER_0_PIN,LOW); - #endif - #if TEMP_1_PIN > -1 - target_bed_raw=0; - if(HEATER_1_PIN > -1) digitalWrite(HEATER_1_PIN,LOW); - #endif - disable_x(); - disable_y(); - disable_z(); - disable_e(); - - if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT); - -} - -inline void manage_inactivity(byte debug) { -if( (millis()-previous_millis_cmd) > max_inactive_time ) if(max_inactive_time) kill(); -if( (millis()-previous_millis_cmd) > stepper_inactive_time ) if(stepper_inactive_time) { disable_x(); disable_y(); disable_z(); disable_e(); } -} - -#ifdef DEBUG -void log_message(char* message) { - Serial.print("DEBUG"); Serial.println(message); -} - -void log_bool(char* message, bool value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_int(char* message, int value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_long(char* message, long value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_float(char* message, float value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_uint(char* message, unsigned int value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_ulong(char* message, unsigned long value) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": "); Serial.println(value); -} - -void log_int_array(char* message, int value[], int array_lenght) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); - for(int i=0; i < array_lenght; i++){ - Serial.print(value[i]); - if(i != array_lenght-1) Serial.print(", "); - } - Serial.println("}"); -} - -void log_long_array(char* message, long value[], int array_lenght) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); - for(int i=0; i < array_lenght; i++){ - Serial.print(value[i]); - if(i != array_lenght-1) Serial.print(", "); - } - Serial.println("}"); -} - -void log_float_array(char* message, float value[], int array_lenght) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); - for(int i=0; i < array_lenght; i++){ - Serial.print(value[i]); - if(i != array_lenght-1) Serial.print(", "); - } - Serial.println("}"); -} - -void log_uint_array(char* message, unsigned int value[], int array_lenght) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); - for(int i=0; i < array_lenght; i++){ - Serial.print(value[i]); - if(i != array_lenght-1) Serial.print(", "); - } - Serial.println("}"); -} - -void log_ulong_array(char* message, unsigned long value[], int array_lenght) { - Serial.print("DEBUG"); Serial.print(message); Serial.print(": {"); - for(int i=0; i < array_lenght; i++){ - Serial.print(value[i]); - if(i != array_lenght-1) Serial.print(", "); - } - Serial.println("}"); -} -#endif diff --git a/Tonokip_Firmware/configuration.h b/Tonokip_Firmware/configuration.h deleted file mode 100644 index 0a38a6a..0000000 --- a/Tonokip_Firmware/configuration.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef PARAMETERS_H -#define PARAMETERS_H - -// NO RS485/EXTRUDER CONTROLLER SUPPORT -// PLEASE VERIFY PIN ASSIGNMENTS FOR YOUR CONFIGURATION!!!!!!! -#define MOTHERBOARD 3 // ATMEGA168 = 0, SANGUINO = 1, MOTHERBOARD = 2, MEGA/RAMPS = 3, ATMEGA328 = 4, Gen6 = 5, Sanguinololu = 6 - -//Comment out to disable SD support -#define SDSUPPORT 1 - -//Min step delay in microseconds. If you are experiencing missing steps, try to raise the delay microseconds, but be aware this -// If you enable this, make sure STEP_DELAY_RATIO is disabled. -//#define STEP_DELAY_MICROS 1 - -//Step delay over interval ratio. If you are still experiencing missing steps, try to uncomment the following line, but be aware this -//If you enable this, make sure STEP_DELAY_MICROS is disabled. -//#define STEP_DELAY_RATIO 0.25 - -//Comment this to disable ramp acceleration -#define RAMP_ACCELERATION 1 - -//Acceleration settings -#ifdef RAMP_ACCELERATION -//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 max_start_speed_units_per_second[] = {25.0,25.0,0.2,10.0}; -long max_acceleration_units_per_sq_second[] = {1000,1000,50,10000}; // X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts -long max_travel_acceleration_units_per_sq_second[] = {500,500,50}; // X, Y, Z max acceleration in mm/s^2 for travel moves -#endif - -// AD595 THERMOCOUPLE SUPPORT UNTESTED... USE WITH CAUTION!!!! - -//PID settings: -//Uncomment the following line to enable PID support. This is untested and could be disastrous. Be careful. -//#define PIDTEMP 1 -#ifdef PIDTEMP -#define PID_MAX 255 // limits current to nozzle -#define PID_INTEGRAL_DRIVE_MAX 220 -#define PID_PGAIN 180 //100 is 1.0 -#define PID_IGAIN 2 //100 is 1.0 -#define PID_DGAIN 100 //100 is 1.0 -#endif - -//How often should the heater check for new temp readings, in milliseconds -#define HEATER_CHECK_INTERVAL 500 -#define BED_CHECK_INTERVAL 5000 -//Comment the following line to enable heat management during acceleration -#define DISABLE_CHECK_DURING_ACC -#ifndef DISABLE_CHECK_DURING_ACC - //Uncomment the following line to disable heat management during the move - //#define DISABLE_CHECK_DURING_MOVE -#endif -//Uncomment the following line to disable heat management during travel moves (and extruder-only moves, eg: retracts), strongly recommended if you are missing steps mid print. -//Probably this should remain commented if are using PID. -//It also defines the max milliseconds interval after which a travel move is not considered so for the sake of this feature. -#define DISABLE_CHECK_DURING_TRAVEL 1000 - -//Experimental temperature smoothing - only uncomment this if your temp readings are noisy -//#define SMOOTHING 1 -//#define SMOOTHFACTOR 16 //best to use a power of two here - determines how many values are averaged together by the smoothing algorithm - -//Experimental watchdog and minimal temp -//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 -//The minimal temperature defines the temperature below which the heater will not be enabled -//#define MINTEMP - -//Experimental max temp -//When temperature exceeds max temp, your bot will halt. -//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 - -// Select one of these only to define how the nozzle temp is read. -#define HEATER_USES_THERMISTOR -//#define HEATER_USES_AD595 -//#define HEATER_USES_MAX6675 - -// Select one of these only to define how the bed temp is read. -#define BED_USES_THERMISTOR -//#define BED_USES_AD595 - -// Calibration formulas -// e_extruded_steps_per_mm = e_feedstock_steps_per_mm * (desired_extrusion_diameter^2 / feedstock_diameter^2) -// new_axis_steps_per_mm = previous_axis_steps_per_mm * (test_distance_instructed/test_distance_traveled) -// units are in millimeters or whatever length unit you prefer: inches,football-fields,parsecs etc - -//Calibration variables -const int NUM_AXIS = 4; // The axis order in all axis related arrays is X, Y, Z, E -bool axis_relative_modes[] = {false, false, false, false}; -float axis_steps_per_unit[] = {80.376,80.376,3200/1.25,16}; // {X steps per unit, Y steps per unit, Z steps per unit, E steps per unit} -//For SAE Prusa mendeel float z_steps_per_unit = should be 3200/1.411 for 5/16-18 rod and 3200/1.058 for 5/16-24 -//float axis_steps_per_unit[] = {10.047,10.047,833.398,0.706}; -float max_feedrate[] = {200000, 200000, 240, 500000}; //mmm, acceleration! - -//For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 -const bool X_ENABLE_ON = 0; -const bool Y_ENABLE_ON = 0; -const bool Z_ENABLE_ON = 0; -const bool E_ENABLE_ON = 0; - -//Disables axis when it's not being used. -const bool DISABLE_X = false; -const bool DISABLE_Y = false; -const bool DISABLE_Z = true; -const bool DISABLE_E = false; - -const bool INVERT_X_DIR = false; -const bool INVERT_Y_DIR = false; -const bool INVERT_Z_DIR = true; -const bool INVERT_E_DIR = false; - -// Sets direction of endstops when homing; 1=MAX, -1=MIN -const int X_HOME_DIR = -1; -const int Y_HOME_DIR = -1; -const int Z_HOME_DIR = -1; - - -//Thermistor settings: - -//Uncomment for 100k thermistor -//#include "ThermistorTable_100k.h" -//#include "BedThermistorTable_100k.h" - -//Uncomment for 200k thermistor -//#include "ThermistorTable_200k.h" -//#include "BedThermistorTable_200k.h" - -//Identical thermistors on heater and bed - use this if you have no heated bed or if the thermistors are the same on both: -#include "ThermistorTable_200k.h" -//#include "ThermistorTable_100k.h" -//#include "ThermistorTable_mendelparts.h" -#define BNUMTEMPS NUMTEMPS -#define bedtemptable temptable - -//Endstop Settings -#define ENDSTOPPULLUPS 1 -const bool ENDSTOPS_INVERTING = false; -const bool min_software_endstops = false; //If true, axis won't move to coordinates less than zero. -const bool max_software_endstops = true; //If true, axis won't move to coordinates greater than the defined lengths below. -const int X_MAX_LENGTH = 220; -const int Y_MAX_LENGTH = 220; -const int Z_MAX_LENGTH = 100; - -#define BAUDRATE 115200 - -//Uncomment the following line to enable debugging. You can better control debugging below the following line -//#define DEBUG -#ifdef DEBUG - //#define DEBUG_PREPARE_MOVE //Enable this to debug prepare_move() function - //#define DEBUG_BRESENHAM //Enable this to debug the Bresenham algorithm - //#define DEBUG_RAMP_ACCELERATION //Enable this to debug all constant acceleration info - //#define DEBUG_MOVE_TIME //Enable this to time each move and print the result - //#define DEBUG_HEAT_MGMT //Enable this to debug heat management. WARNING, this will cause axes to jitter! - //#define DEBUG_DISABLE_CHECK_DURING_TRAVEL //Debug the namesake feature, see above in this file -#endif - -#endif diff --git a/Tonokip_Firmware/createTemperatureLookup.py b/Tonokip_Firmware/createTemperatureLookup.py deleted file mode 100644 index e60a490..0000000 --- a/Tonokip_Firmware/createTemperatureLookup.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/python -# -# Creates a C code lookup table for doing ADC to temperature conversion -# on a microcontroller -# based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html -"""Thermistor Value Lookup Table Generator - -Generates lookup to temperature values for use in a microcontroller in C format based on: -http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html - -The main use is for Arduino programs that read data from the circuit board described here: -http://make.rrrf.org/ts-1.0 - -Usage: python createTemperatureLookup.py [options] - -Options: - -h, --help show this help - --r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000) - --t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet) - --beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta - --r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000) - --r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000) - --num-temps=... the number of temperature points to calculate (default: 20) - --max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values -""" - -from math import * -import sys -import getopt - -class Thermistor: - "Class to do the thermistor maths" - def __init__(self, r0, t0, beta, r1, r2): - self.r0 = r0 # stated resistance, e.g. 10K - self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C - self.beta = beta # stated beta, e.g. 3500 - self.vadc = 5.0 # ADC reference - self.vcc = 5.0 # supply voltage to potential divider - self.k = r0 * exp(-beta / self.t0) # constant part of calculation - - if r1 > 0: - self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage - self.rs = r1 * r2 / (r1 + r2) # effective bias impedance - else: - self.vs = self.vcc # effective bias voltage - self.rs = r2 # effective bias impedance - - def temp(self,adc): - "Convert ADC reading into a temperature in Celcius" - v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage - r = self.rs * v / (self.vs - v) # resistance of thermistor - return (self.beta / log(r / self.k)) - 273.15 # temperature - - def setting(self, t): - "Convert a temperature into a ADC value" - r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor - v = self.vs * r / (self.rs + r) # the voltage at the potential divider - return round(v / self.vadc * 1024) # the ADC reading - -def main(argv): - - r0 = 10000; - t0 = 25; - beta = 3947; - r1 = 680; - r2 = 1600; - num_temps = int(20); - - try: - opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2="]) - except getopt.GetoptError: - usage() - sys.exit(2) - - for opt, arg in opts: - if opt in ("-h", "--help"): - usage() - sys.exit() - elif opt == "--r0": - r0 = int(arg) - elif opt == "--t0": - t0 = int(arg) - elif opt == "--beta": - beta = int(arg) - elif opt == "--r1": - r1 = int(arg) - elif opt == "--r2": - r2 = int(arg) - - if r1: - max_adc = int(1023 * r1 / (r1 + r2)); - else: - max_adc = 1023 - increment = int(max_adc/(num_temps-1)); - - t = Thermistor(r0, t0, beta, r1, r2) - - adcs = range(1, max_adc, increment); -# adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300] - first = 1 - - print "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)" - print "// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)" - print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc) - print "// r0: %s" % (r0) - print "// t0: %s" % (t0) - print "// r1: %s" % (r1) - print "// r2: %s" % (r2) - print "// beta: %s" % (beta) - print "// max adc: %s" % (max_adc) - print "#define NUMTEMPS %s" % (len(adcs)) - print "short temptable[NUMTEMPS][2] = {" - - counter = 0 - for adc in adcs: - counter = counter +1 - if counter == len(adcs): - print " {%s, %s}" % (adc, int(t.temp(adc))) - else: - print " {%s, %s}," % (adc, int(t.temp(adc))) - print "};" - -def usage(): - print __doc__ - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/Tonokip_Firmware/pins.h b/Tonokip_Firmware/pins.h deleted file mode 100644 index eee78e8..0000000 --- a/Tonokip_Firmware/pins.h +++ /dev/null @@ -1,477 +0,0 @@ -#ifndef PINS_H -#define PINS_H - -/**************************************************************************************** -* Arduino pin assignment -* -* ATMega168 -* +-\/-+ -* PC6 1| |28 PC5 (AI 5 / D19) -* (D 0) PD0 2| |27 PC4 (AI 4 / D18) -* (D 1) PD1 3| |26 PC3 (AI 3 / D17) -* (D 2) PD2 4| |25 PC2 (AI 2 / D16) -* PWM+ (D 3) PD3 5| |24 PC1 (AI 1 / D15) -* (D 4) PD4 6| |23 PC0 (AI 0 / D14) -* VCC 7| |22 GND -* GND 8| |21 AREF -* PB6 9| |20 AVCC -* PB7 10| |19 PB5 (D 13) -* PWM+ (D 5) PD5 11| |18 PB4 (D 12) -* PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM -* (D 7) PD7 13| |16 PB2 (D 10) PWM -* (D 8) PB0 14| |15 PB1 (D 9) PWM -* +----+ -****************************************************************************************/ -#if MOTHERBOARD == 0 -#ifndef __AVR_ATmega168__ -#error Oops! Make sure you have 'Arduino Diecimila' selected from the boards menu. -#endif - -#define X_STEP_PIN 2 -#define X_DIR_PIN 3 -#define X_ENABLE_PIN -1 -#define X_MIN_PIN 4 -#define X_MAX_PIN 9 - -#define Y_STEP_PIN 10 -#define Y_DIR_PIN 7 -#define Y_ENABLE_PIN -1 -#define Y_MIN_PIN 8 -#define Y_MAX_PIN 13 - -#define Z_STEP_PIN 19 -#define Z_DIR_PIN 18 -#define Z_ENABLE_PIN 5 -#define Z_MIN_PIN 17 -#define Z_MAX_PIN 16 - -#define E_STEP_PIN 11 -#define E_DIR_PIN 12 -#define E_ENABLE_PIN -1 - -#define SDPOWER -1 -#define SDSS -1 -#define LED_PIN -1 -#define FAN_PIN -1 -#define PS_ON_PIN 15 -#define KILL_PIN -1 - -#define HEATER_0_PIN 6 -#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! - - - - - - -/**************************************************************************************** -* Sanguino/RepRap Motherboard with direct-drive extruders -* -* ATMega644P -* -* +---\/---+ -* (D 0) PB0 1| |40 PA0 (AI 0 / D31) -* (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 -* INT0 RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS -* INT1 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 -* +--------+ -* -****************************************************************************************/ -#elif MOTHERBOARD == 1 -#ifndef __AVR_ATmega644P__ -#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. -#endif - -#define X_STEP_PIN 15 -#define X_DIR_PIN 18 -#define X_ENABLE_PIN 19 -#define X_MIN_PIN 20 -#define X_MAX_PIN 21 - -#define Y_STEP_PIN 23 -#define Y_DIR_PIN 22 -#define Y_ENABLE_PIN 19 -#define Y_MIN_PIN 25 -#define Y_MAX_PIN 26 - -#define Z_STEP_PIN 29 -#define Z_DIR_PIN 30 -#define Z_ENABLE_PIN 31 -#define Z_MIN_PIN 2 -#define Z_MAX_PIN 1 - -#define E_STEP_PIN 12 -#define E_DIR_PIN 16 -#define E_ENABLE_PIN 3 - -#define SDPOWER -1 -#define SDSS -1 -#define LED_PIN 0 -#define FAN_PIN -1 -#define PS_ON_PIN -1 -#define KILL_PIN -1 - -#define HEATER_0_PIN 14 -#define TEMP_0_PIN 4 //D27 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! - -/* Unused (1) (2) (3) 4 5 6 7 8 9 10 11 12 13 (14) (15) (16) 17 (18) (19) (20) (21) (22) (23) 24 (25) (26) (27) 28 (29) (30) (31) */ - - - - - - -/**************************************************************************************** -* RepRap Motherboard ****---NOOOOOO RS485/EXTRUDER CONTROLLER!!!!!!!!!!!!!!!!!---******* -* -****************************************************************************************/ -#elif MOTHERBOARD == 2 -#ifndef __AVR_ATmega644P__ -#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. -#endif - -#define X_STEP_PIN 15 -#define X_DIR_PIN 18 -#define X_ENABLE_PIN 19 -#define X_MIN_PIN 20 -#define X_MAX_PIN 21 - -#define Y_STEP_PIN 23 -#define Y_DIR_PIN 22 -#define Y_ENABLE_PIN 24 -#define Y_MIN_PIN 25 -#define Y_MAX_PIN 26 - -#define Z_STEP_PINN 27 -#define Z_DIR_PINN 28 -#define Z_ENABLE_PIN 29 -#define Z_MIN_PIN 30 -#define Z_MAX_PIN 31 - -#define E_STEP_PIN 17 -#define E_DIR_PIN 16 -#define E_ENABLE_PIN -1 - -#define SDPOWER -1 -#define SDSS 4 -#define LED_PIN 0 - -#define SD_CARD_WRITE 2 -#define SD_CARD_DETECT 3 -#define SD_CARD_SELECT 4 - -//our RS485 pins -#define TX_ENABLE_PIN 12 -#define RX_ENABLE_PIN 13 - -//pin for controlling the PSU. -#define PS_ON_PIN 14 - -#define FAN_PIN -1 -#define KILL_PIN -1 - -#define HEATER_0_PIN -1 -#define TEMP_0_PIN -1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! - - - - - - -/**************************************************************************************** -* Arduino Mega pin assignment -* -****************************************************************************************/ -#elif MOTHERBOARD == 3 -//////////////////FIX THIS////////////// -#ifndef __AVR_ATmega1280__ - #ifndef __AVR_ATmega2560__ - #error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu. - #endif -#endif - -// uncomment one of the following lines for RAMPS v1.3 or v1.0, comment both for v1.2 or 1.1 -// #define RAMPS_V_1_3 -// #define RAMPS_V_1_0 - - -#ifdef RAMPS_V_1_3 - -#define X_STEP_PIN 54 -#define X_DIR_PIN 55 -#define X_ENABLE_PIN 38 -#define X_MIN_PIN 3 -#define X_MAX_PIN -1 //2 //Max endstops default to disabled "-1", set to commented value to enable. - -#define Y_STEP_PIN 60 -#define Y_DIR_PIN 61 -#define Y_ENABLE_PIN 56 -#define Y_MIN_PIN 14 -#define Y_MAX_PIN -1 //15 - -#define Z_STEP_PIN 46 -#define Z_DIR_PIN 48 -#define Z_ENABLE_PIN 62 -#define Z_MIN_PIN 18 -#define Z_MAX_PIN -1 //19 - -#define E_STEP_PIN 26 -#define E_DIR_PIN 28 -#define E_ENABLE_PIN 24 - -#define SDPOWER -1 -#define SDSS 53 -#define LED_PIN 13 -#define FAN_PIN 9 -#define PS_ON_PIN 12 -#define KILL_PIN -1 - -#define HEATER_0_PIN 10 -#define HEATER_1_PIN 8 -#define TEMP_0_PIN 13 // ANALOG NUMBERING -#define TEMP_1_PIN 14 // ANALOG NUMBERING - - -#else // RAMPS_V_1_1 or RAMPS_V_1_2 as default - -#define X_STEP_PIN 26 -#define X_DIR_PIN 28 -#define X_ENABLE_PIN 24 -#define X_MIN_PIN 3 -#define X_MAX_PIN -1 //2 - -#define Y_STEP_PIN 38 -#define Y_DIR_PIN 40 -#define Y_ENABLE_PIN 36 -#define Y_MIN_PIN 16 -#define Y_MAX_PIN -1 //17 - -#define Z_STEP_PIN 44 -#define Z_DIR_PIN 46 -#define Z_ENABLE_PIN 42 -#define Z_MIN_PIN 18 -#define Z_MAX_PIN -1 //19 - -#define E_STEP_PIN 32 -#define E_DIR_PIN 34 -#define E_ENABLE_PIN 30 - -#define SDPOWER 48 -#define SDSS 53 -#define LED_PIN 13 -#define PS_ON_PIN -1 -#define KILL_PIN -1 - - - -#ifdef RAMPS_V_1_0 // RAMPS_V_1_0 - #define HEATER_0_PIN 12 // RAMPS 1.0 - #define HEATER_1_PIN -1 // RAMPS 1.0 - #define FAN_PIN 11 // RAMPS 1.0 - -#else // RAMPS_V_1_1 or RAMPS_V_1_2 - #define HEATER_0_PIN 10 // RAMPS 1.1 - #define HEATER_1_PIN 8 // RAMPS 1.1 - #define FAN_PIN 9 // RAMPS 1.1 -#endif - -#define TEMP_0_PIN 2 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! -#define TEMP_1_PIN 1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! -#endif - -// SPI for Max6675 Thermocouple - -#ifndef SDSUPPORT -// these pins are defined in the SD library if building with SD support #define SCK_PIN 52 - #define MISO_PIN 50 - #define MOSI_PIN 51 - #define MAX6675_SS 53 -#else - #define MAX6675_SS 49 -#endif - - - -/**************************************************************************************** -* Duemilanove w/ ATMega328P pin assignment -* -****************************************************************************************/ -#elif MOTHERBOARD == 4 -#ifndef __AVR_ATmega328P__ -#error Oops! Make sure you have 'Arduino Duemilanove w/ ATMega328' selected from the 'Tools -> Boards' menu. -#endif - -#define X_STEP_PIN 19 -#define X_DIR_PIN 18 -#define X_ENABLE_PIN -1 -#define X_MIN_PIN 17 -#define X_MAX_PIN -1 - -#define Y_STEP_PIN 10 -#define Y_DIR_PIN 7 -#define Y_ENABLE_PIN -1 -#define Y_MIN_PIN 8 -#define Y_MAX_PIN -1 - -#define Z_STEP_PIN 13 -#define Z_DIR_PIN 3 -#define Z_ENABLE_PIN 2 -#define Z_MIN_PIN 4 -#define Z_MAX_PIN -1 - -#define E_STEP_PIN 11 -#define E_DIR_PIN 12 -#define E_ENABLE_PIN -1 - -#define SDPOWER -1 -#define SDSS -1 -#define LED_PIN -1 -#define FAN_PIN 5 -#define PS_ON_PIN -1 -#define KILL_PIN -1 - -#define HEATER_0_PIN 6 -#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! - - - - -/**************************************************************************************** -* Gen6 pin assignment -* -****************************************************************************************/ -#elif MOTHERBOARD == 5 - -#ifndef __AVR_ATmega644P__ - #error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. -#endif - -//x axis pins - #define X_STEP_PIN 15 - #define X_DIR_PIN 18 - #define X_ENABLE_PIN 19 - #define X_MIN_PIN 20 - #define X_MAX_PIN -1 - - //y axis pins - #define Y_STEP_PIN 23 - #define Y_DIR_PIN 22 - #define Y_ENABLE_PIN 24 - #define Y_MIN_PIN 25 - #define Y_MAX_PIN -1 - - //z axis pins - #define Z_STEP_PIN 27 - #define Z_DIR_PIN 28 - #define Z_ENABLE_PIN 29 - #define Z_MIN_PIN 30 - #define Z_MAX_PIN -1 - - //extruder pins - #define E_STEP_PIN 4 //Edited @ EJE Electronics 20100715 - #define E_DIR_PIN 2 //Edited @ EJE Electronics 20100715 - #define E_ENABLE_PIN 3 //Added @ EJE Electronics 20100715 - #define TEMP_0_PIN 5 //changed @ rkoeppl 20110410 - #define HEATER_0_PIN 14 //changed @ rkoeppl 20110410 - #define HEATER_1_PIN -1 //changed @ rkoeppl 20110410 - - - #define SDPOWER -1 - #define SDSS -1 - #define LED_PIN -1 //changed @ rkoeppl 20110410 - #define TEMP_1_PIN -1 //changed @ rkoeppl 20110410 - #define FAN_PIN -1 //changed @ rkoeppl 20110410 - #define PS_ON_PIN -1 //changed @ rkoeppl 20110410 - //our pin for debugging. - - #define DEBUG_PIN 0 - - //our RS485 pins - #define TX_ENABLE_PIN 12 - #define RX_ENABLE_PIN 13 - - -/**************************************************************************************** -* Sanguinololu pin assignment -* -****************************************************************************************/ -#elif MOTHERBOARD == 6 -#ifndef __AVR_ATmega644P__ -#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. -#endif - -// uncomment the following line for Sanguinololu v1.2, comment for 1.1 or earlier. -// #define SANGUINOLOLU_V_1_2 - - -#define X_STEP_PIN 15 -#define X_DIR_PIN 21 -#define X_ENABLE_PIN -1 -#define X_MIN_PIN 18 -#define X_MAX_PIN -2 //2 - -#define Y_STEP_PIN 22 -#define Y_DIR_PIN 23 -#define Y_ENABLE_PIN -1 -#define Y_MIN_PIN 19 -#define Y_MAX_PIN -1 //17 - -#define Z_STEP_PIN 3 -#define Z_DIR_PIN 2 -// zenable defined by platform below -#define Z_MIN_PIN 20 -#define Z_MAX_PIN -1 //19 - -#define E_STEP_PIN 1 -#define E_DIR_PIN 0 -#define E_ENABLE_PIN -1 - -#define LED_PIN -1 - -#define FAN_PIN -1 // THIS LINE FOR V1.0 - -#define PS_ON_PIN -1 -#define KILL_PIN -1 - -#define HEATER_0_PIN 13 // THIS LINE FOR V1.0+ (extruder) - -#ifdef SANGUINOLOLU_V_1_2 - -#define HEATER_1_PIN 12 // (bed) -#define Z_ENABLE_PIN 26 - -#else - -#define HEATER_1_PIN 14 // (bed) -#define Z_ENABLE_PIN -1 - -#endif - -#define TEMP_0_PIN 7 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 33 extruder) -#define TEMP_1_PIN 6 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed) -#define SDPOWER -1 -#define SDSS 31 - -#else - -#error Unknown MOTHERBOARD value in configuration.h - -#endif - -#endif -- cgit v1.2.1