| #if WAIT_TO_START | #if WAIT_TO_START | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // Discard input. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while(Serial.read() >= 0); | |||||
| } while(Serial.available() && Serial.read() >= 0); | |||||
| #endif // WAIT_TO_START | #endif // WAIT_TO_START | ||||
| #if USE_DS1307 | #if USE_DS1307 |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("type any character to start"); | Serial.println("type any character to start"); | ||||
| while (Serial.read() < 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| if (!sd.begin()) { | if (!sd.begin()) { |
| uint32_t minLatency; | uint32_t minLatency; | ||||
| uint32_t totalLatency; | uint32_t totalLatency; | ||||
| while (Serial.read() >= 0) { | |||||
| } | |||||
| // Read any existing Serial data. | |||||
| do { | |||||
| delay(10); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F() stores strings in flash to save RAM | // F() stores strings in flash to save RAM | ||||
| Serial.println(F("Type any character to start")); | Serial.println(F("Type any character to start")); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| yield(); | yield(); | ||||
| } | } | ||||
| } | } | ||||
| // F() stores strings in flash to save RAM | // F() stores strings in flash to save RAM | ||||
| cout << endl << F("Type any character to start\n"); | cout << endl << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| } | } | ||||
| // F() stores strings in flash to save RAM | // F() stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| uint32_t minLatency; | uint32_t minLatency; | ||||
| uint32_t totalLatency; | uint32_t totalLatency; | ||||
| // discard any input | |||||
| // Discard any input. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F() stores strings in flash to save RAM | // F() stores strings in flash to save RAM | ||||
| Serial.println(F("Type any character to start")); | Serial.println(F("Type any character to start")); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| yield(); | yield(); | ||||
| } | } | ||||
| if (!SD.begin(chipSelect)) { | if (!SD.begin(chipSelect)) { |
| } | } | ||||
| // F() stores strings in flash to save RAM | // F() stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| delay(400); // catch Due reset problem | delay(400); // catch Due reset problem |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| void loop(void) { | void loop(void) { | ||||
| // discard any input | |||||
| // Read any Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| Serial.println(); | Serial.println(); | ||||
| Serial.println(F("type:")); | Serial.println(F("type:")); | ||||
| Serial.println(F("c - convert file to csv")); | Serial.println(F("c - convert file to csv")); | ||||
| if (ERROR_LED_PIN >= 0) { | if (ERROR_LED_PIN >= 0) { | ||||
| digitalWrite(ERROR_LED_PIN, LOW); | digitalWrite(ERROR_LED_PIN, LOW); | ||||
| } | } | ||||
| // Read any extra Serial data. | |||||
| // Read any Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| if (c == 'c') { | if (c == 'c') { | ||||
| binaryToCsv(); | binaryToCsv(); |
| void loop() { | void loop() { | ||||
| int c; | int c; | ||||
| // Discard any Serial input. | |||||
| while (Serial.read() > 0) {} | |||||
| // Read any existing Serial data. | |||||
| do { | |||||
| delay(10); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| Serial.print(F("\r\nEnter File Number: ")); | Serial.print(F("\r\nEnter File Number: ")); | ||||
| while ((c = Serial.read()) < 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| c = Serial.read(); | |||||
| uint8_t i = c - '0'; | uint8_t i = c - '0'; | ||||
| if (!isdigit(c) || i >= n) { | if (!isdigit(c) || i >= n) { | ||||
| Serial.println(F("Invald number")); | Serial.println(F("Invald number")); |
| #include <SPI.h> | #include <SPI.h> | ||||
| #include "SdFat.h" | #include "SdFat.h" | ||||
| #include "FreeStack.h" | #include "FreeStack.h" | ||||
| #include "UserDataType.h" // Edit this include file to change data_t. | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // Set useSharedSpi true for use of an SPI sensor. | // Set useSharedSpi true for use of an SPI sensor. | ||||
| const bool useSharedSpi = false; | const bool useSharedSpi = false; | ||||
| uint32_t startMicros; | uint32_t startMicros; | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // User data functions. Modify these functions for your data items. | // User data functions. Modify these functions for your data items. | ||||
| #include "UserDataType.h" // Edit this include file to change data_t. | |||||
| // Acquire a data record. | // Acquire a data record. | ||||
| void acquireData(data_t* data) { | void acquireData(data_t* data) { | ||||
| // Digital pin to indicate an error, set to -1 if not used. | // Digital pin to indicate an error, set to -1 if not used. | ||||
| // The led blinks for fatal errors. The led goes on solid for SD write | // The led blinks for fatal errors. The led goes on solid for SD write | ||||
| // overrun errors and logging continues. | // overrun errors and logging continues. | ||||
| #undef ERROR_LED_PIN | |||||
| const int8_t ERROR_LED_PIN = -1; | const int8_t ERROR_LED_PIN = -1; | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // File definitions. | // File definitions. | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| void loop(void) { | void loop(void) { | ||||
| // discard any input | |||||
| // Read any Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| Serial.println(); | Serial.println(); | ||||
| Serial.println(F("type:")); | Serial.println(F("type:")); | ||||
| Serial.println(F("c - convert file to csv")); | Serial.println(F("c - convert file to csv")); | ||||
| // Discard extra Serial data. | // Discard extra Serial data. | ||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| if (ERROR_LED_PIN >= 0) { | if (ERROR_LED_PIN >= 0) { | ||||
| digitalWrite(ERROR_LED_PIN, LOW); | digitalWrite(ERROR_LED_PIN, LOW); |
| } | } | ||||
| Serial.println("Type any character to start"); | Serial.println("Type any character to start"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| uint32_t minLatency; | uint32_t minLatency; | ||||
| uint32_t totalLatency; | uint32_t totalLatency; | ||||
| while (Serial.read() >= 0) { | |||||
| } | |||||
| // Read any existing Serial data. | |||||
| do { | |||||
| delay(10); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F stores strings in flash to save RAM | // F stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | |||||
| } | } | ||||
| delay(400); // catch Due reset problem | delay(400); // catch Due reset problem | ||||
| bool firstTry = true; | bool firstTry = true; | ||||
| void loop() { | void loop() { | ||||
| // read any existing Serial data | |||||
| // Read any existing Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| if (!firstTry) { | if (!firstTry) { | ||||
| cout << F("\nRestarting\n"); | cout << F("\nRestarting\n"); | ||||
| reformatMsg(); | reformatMsg(); | ||||
| return; | return; | ||||
| } | } | ||||
| // read any existing Serial data | |||||
| while (Serial.read() >= 0) {} | |||||
| // Read any extra Serial data. | |||||
| do { | |||||
| delay(10); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| cout << F("\nSuccess! Type any character to restart.\n"); | cout << F("\nSuccess! Type any character to restart.\n"); | ||||
| while (Serial.read() < 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| } | } |
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| void loop(void) { | void loop(void) { | ||||
| // Read any extra Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F stores strings in flash to save RAM | // F stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("Type any character to start"); | Serial.println("Type any character to start"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // Initialize the SD. | // Initialize the SD. |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("Type any character to start"); | Serial.println("Type any character to start"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // Initialize the SD. | // Initialize the SD. |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("Type any character to start"); | Serial.println("Type any character to start"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // Initialize SdFat or print a detailed error message and halt | // Initialize SdFat or print a detailed error message and halt |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // Discard any extra characters. | // Discard any extra characters. | ||||
| do {delay(10);} while (Serial.read() >= 0); | |||||
| do { | |||||
| delay(10); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| cout << F( | cout << F( | ||||
| "\n" | "\n" | ||||
| "This program can erase and/or format SD/SDHC cards.\n" | "This program can erase and/or format SD/SDHC cards.\n" | ||||
| cout << F("Quiting, you did not enter 'Y'.\n"); | cout << F("Quiting, you did not enter 'Y'.\n"); | ||||
| return; | return; | ||||
| } | } | ||||
| // read any existing Serial data | |||||
| // Read any existing Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| cout << F( | cout << F( | ||||
| "\n" | "\n" |
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| void loop() { | void loop() { | ||||
| // read any existing Serial data | |||||
| // Read any existing Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F stores strings in flash to save RAM | // F stores strings in flash to save RAM | ||||
| cout << F("\ntype any character to start\n"); | cout << F("\ntype any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("Type any character to start"); | Serial.println("Type any character to start"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| buf[i] = i; | buf[i] = i; | ||||
| } | } | ||||
| Serial.println(F("type any character to start")); | Serial.println(F("type any character to start")); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // disable sd2 while initializing sd1 | // disable sd2 while initializing sd1 |
| } | } | ||||
| Serial.println(F("type any character to start")); | Serial.println(F("type any character to start")); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| } | } | ||||
| // F stores strings in flash to save RAM | // F stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with |
| const uint32_t FILE_SIZE_MB = 5; | const uint32_t FILE_SIZE_MB = 5; | ||||
| // Write pass count. | // Write pass count. | ||||
| const uint8_t WRITE_COUNT = 10; | |||||
| const uint8_t WRITE_COUNT = 2; | |||||
| // Read pass count. | // Read pass count. | ||||
| const uint8_t READ_COUNT = 5; | |||||
| const uint8_t READ_COUNT = 2; | |||||
| //============================================================================== | //============================================================================== | ||||
| // End of configuration constants. | // End of configuration constants. | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // file system | // file system | ||||
| SdFat sd; | SdFat sd; | ||||
| // Set SD_SPI_CONFIGURATION to three to test next two definitions. | |||||
| // SdFatLibSpi sd; | |||||
| // Args are misoPin, mosiPin, sckPin. | |||||
| // SdFatSoftSpi<6, 7, 5> sd; | |||||
| // test file | // test file | ||||
| SdFile file; | SdFile file; | ||||
| uint32_t minLatency; | uint32_t minLatency; | ||||
| uint32_t totalLatency; | uint32_t totalLatency; | ||||
| // discard any input | |||||
| // Discard any input. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| // F( stores strings in flash to save RAM | // F( stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) { | if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) { | ||||
| error("file.open"); | error("file.open"); | ||||
| } | } | ||||
| // Read any Serial data. | |||||
| do { | do { | ||||
| delay(10); | delay(10); | ||||
| } while (Serial.read() >= 0); | |||||
| } while (Serial.available() && Serial.read() >= 0); | |||||
| Serial.print(F("Logging to: ")); | Serial.print(F("Logging to: ")); | ||||
| Serial.println(fileName); | Serial.println(fileName); |
| } | } | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) {} | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | |||||
| } | |||||
| delay(400); // catch Due reset problem | delay(400); // catch Due reset problem | ||||
| // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with |
| // F stores strings in flash to save RAM | // F stores strings in flash to save RAM | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) {} | |||||
| delay(400); // catch Due reset problem | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | |||||
| } | |||||
| // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | ||||
| // breadboards. use SPI_FULL_SPEED for better performance. | // breadboards. use SPI_FULL_SPEED for better performance. |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| cout << F("Type any character to start\n"); | cout << F("Type any character to start\n"); | ||||
| while (Serial.read() <= 0) {} | |||||
| delay(400); // catch Due reset problem | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | |||||
| } | |||||
| // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with | ||||
| // breadboards. use SPI_FULL_SPEED for better performance | // breadboards. use SPI_FULL_SPEED for better performance |
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| cout << F("Insert an empty SD. Type any character to start.") << endl; | cout << F("Insert an empty SD. Type any character to start.") << endl; | ||||
| while (Serial.read() <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| Serial.println("Type 'Y' to wipe all data."); | Serial.println("Type 'Y' to wipe all data."); | ||||
| while ((c = Serial.read()) <= 0) { | |||||
| while (!Serial.available()) { | |||||
| SysCall::yield(); | SysCall::yield(); | ||||
| } | } | ||||
| c = Serial.read(); | |||||
| if (c != 'Y') { | if (c != 'Y') { | ||||
| sd.errorHalt("Quitting, you did not type 'Y'."); | sd.errorHalt("Quitting, you did not type 'Y'."); | ||||
| } | } |
| #endif // ARDUINO | #endif // ARDUINO | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** SdFat version YYYYMMDD */ | /** SdFat version YYYYMMDD */ | ||||
| #define SD_FAT_VERSION 20160411 | |||||
| #define SD_FAT_VERSION 20160422 | |||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| * \class SdBaseFile | * \class SdBaseFile |
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** Set pin value | /** Set pin value | ||||
| * @param[in] pin Arduino pin number | * @param[in] pin Arduino pin number | ||||
| * @param[in] level value to write | |||||
| * @param[in] val value to write | |||||
| */ | */ | ||||
| static inline __attribute__((always_inline)) | static inline __attribute__((always_inline)) | ||||
| void fastDigitalWrite(uint8_t pin, uint8_t val) { | void fastDigitalWrite(uint8_t pin, uint8_t val) { | ||||
| if(pin < 16){ | |||||
| if(val) GPOS = (1 << pin); | |||||
| else GPOC = (1 << pin); | |||||
| } else if(pin == 16){ | |||||
| if(val) GP16O |= 1; | |||||
| else GP16O &= ~1; | |||||
| if (pin < 16) { | |||||
| if (val) { | |||||
| GPOS = (1 << pin); | |||||
| } else { | |||||
| GPOC = (1 << pin); | |||||
| } | |||||
| } else if (pin == 16) { | |||||
| if (val) { | |||||
| GP16O |= 1; | |||||
| } else { | |||||
| GP16O &= ~1; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** read pin value | |||||
| /** Read pin value | |||||
| * @param[in] pin Arduino pin number | * @param[in] pin Arduino pin number | ||||
| * @return value read | * @return value read | ||||
| */ | */ | ||||
| static inline __attribute__((always_inline)) | static inline __attribute__((always_inline)) | ||||
| bool fastDigitalRead(uint8_t pin) { | bool fastDigitalRead(uint8_t pin) { | ||||
| if(pin < 16){ | |||||
| if (pin < 16) { | |||||
| return GPIP(pin); | return GPIP(pin); | ||||
| } else if(pin == 16){ | |||||
| } else if (pin == 16) { | |||||
| return GP16I & 0x01; | return GP16I & 0x01; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| fastDigitalWrite(pin, !fastDigitalRead(pin)); | fastDigitalWrite(pin, !fastDigitalRead(pin)); | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| inline void fastPinMode(uint8_t pin, uint8_t mode) {pinMode(pin, mode);} | |||||
| #define fastPinMode(pin, mode) pinMode(pin, mode) | |||||
| #endif // __AVR__ | #endif // __AVR__ | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** set pin configuration | /** set pin configuration | ||||
| * @param[in] level If mode is output, set level high/low. | * @param[in] level If mode is output, set level high/low. | ||||
| * If mode is input, enable or disable the pin's 20K pullup. | * If mode is input, enable or disable the pin's 20K pullup. | ||||
| */ | */ | ||||
| static inline __attribute__((always_inline)) | |||||
| void fastPinConfig(uint8_t pin, uint8_t mode, bool level) { | |||||
| fastPinMode(pin, mode); | |||||
| fastDigitalWrite(pin, level); | |||||
| } | |||||
| #define fastPinConfig(pin, mode, level)\ | |||||
| {fastPinMode(pin, mode); fastDigitalWrite(pin, level);} | |||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| * @class DigitalPin | * @class DigitalPin |
| /* Arduino SdSpi Library | /* Arduino SdSpi Library | ||||
| * Copyright (C) 2013 by William Greiman | * Copyright (C) 2013 by William Greiman | ||||
| * | * | ||||
| * STM32F1 code for Maple and Maple Mini support, 2015 by Victor Perez | |||||
| * | |||||
| * This file is part of the Arduino SdSpi Library | * This file is part of the Arduino SdSpi Library | ||||
| * | * | ||||
| * This Library is free software: you can redistribute it and/or modify | * This Library is free software: you can redistribute it and/or modify | ||||
| */ | */ | ||||
| #if defined(__STM32F1__) | #if defined(__STM32F1__) | ||||
| #include "SdSpi.h" | #include "SdSpi.h" | ||||
| #include <libmaple/dma.h> | |||||
| /** Use STM32 DMAC if nonzero */ | |||||
| #define USE_STM32F1_DMAC 1 | #define USE_STM32F1_DMAC 1 | ||||
| /** Time in ms for DMA receive timeout */ | |||||
| #define STM32F1_DMA_TIMEOUT 100 | |||||
| /** DMAC receive channel */ | |||||
| #define SPI1_DMAC_RX_CH DMA_CH2 | |||||
| /** DMAC transmit channel */ | |||||
| #define SPI1_DMAC_TX_CH DMA_CH3 | |||||
| volatile bool SPI_DMA_TX_Active = false; | |||||
| volatile bool SPI_DMA_RX_Active = false; | |||||
| /** ISR for DMA TX event. */ | |||||
| inline void SPI_DMA_TX_Event() { | |||||
| SPI_DMA_TX_Active = false; | |||||
| dma_disable(DMA1, SPI_DMAC_TX_CH); | |||||
| } | |||||
| /** ISR for DMA RX event. */ | |||||
| inline void SPI_DMA_RX_Event() { | |||||
| SPI_DMA_RX_Active = false; | |||||
| dma_disable(DMA1, SPI1_DMAC_RX_CH); | |||||
| } | |||||
| //------------------------------------------------------------------------------ | |||||
| /** Disable DMA Channel. */ | |||||
| static void dmac_channel_disable(dma_channel ul_num) { | |||||
| dma_disable(DMA1, ul_num); | |||||
| } | |||||
| /** Enable DMA Channel. */ | |||||
| static void dmac_channel_enable(dma_channel ul_num) { | |||||
| dma_enable(DMA1, ul_num); | |||||
| } | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** Initialize the SPI bus. | |||||
| * | |||||
| * \param[in] chipSelectPin SD card chip select pin. | |||||
| */ | |||||
| void SdSpi::begin(uint8_t chipSelectPin) { | void SdSpi::begin(uint8_t chipSelectPin) { | ||||
| pinMode(chipSelectPin, OUTPUT); | pinMode(chipSelectPin, OUTPUT); | ||||
| digitalWrite(chipSelectPin, HIGH); | digitalWrite(chipSelectPin, HIGH); | ||||
| SPI.begin(); | SPI.begin(); | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // start RX DMA | |||||
| static void spiDmaRX(uint8_t* dst, uint16_t count) { | |||||
| // spi_rx_dma_enable(SPI1); | |||||
| if (count < 1) return; | |||||
| dma_setup_transfer(DMA1, SPI1_DMAC_RX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS, | |||||
| dst, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT)); | |||||
| dma_set_num_transfers(DMA1, SPI1_DMAC_RX_CH, count); // 2 bytes per pixel | |||||
| SPI_DMA_RX_Active = true; | |||||
| dma_enable(DMA1, SPI1_DMAC_RX_CH); | |||||
| } | |||||
| //------------------------------------------------------------------------------ | |||||
| // start TX DMA | |||||
| static void spiDmaTX(const uint8_t* src, uint16_t count) { | |||||
| if (count < 1) return; | |||||
| static uint8_t ff = 0XFF; | |||||
| if (!src) { | |||||
| src = &ff; | |||||
| dma_setup_transfer(DMA1, SPI1_DMAC_TX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS, | |||||
| const_cast<uint8_t*>(src), DMA_SIZE_8BITS, | |||||
| (DMA_FROM_MEM | DMA_TRNS_CMPLT)); | |||||
| } else { | |||||
| dma_setup_transfer(DMA1, SPI1_DMAC_TX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS, | |||||
| const_cast<uint8_t*>(src), DMA_SIZE_8BITS, | |||||
| (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT)); | |||||
| } | |||||
| dma_set_num_transfers(DMA1, SPI1_DMAC_TX_CH, count); // 2 bytes per pixel | |||||
| SPI_DMA_TX_Active = true; | |||||
| dma_enable(DMA1, SPI1_DMAC_TX_CH); | |||||
| } | |||||
| //------------------------------------------------------------------------------ | |||||
| // initialize SPI controller STM32F1 | |||||
| void SdSpi::beginTransaction(uint8_t sckDivisor) { | |||||
| /** Set SPI options for access to SD/SDHC cards. | |||||
| * | |||||
| * \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock. | |||||
| */ | |||||
| void SdSpi::beginTransaction(uint8_t divisor) { | |||||
| #if ENABLE_SPI_TRANSACTIONS | #if ENABLE_SPI_TRANSACTIONS | ||||
| SPI.beginTransaction(SPISettings()); | |||||
| // Correct divisor will be set below. | |||||
| SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); | |||||
| #endif // ENABLE_SPI_TRANSACTIONS | #endif // ENABLE_SPI_TRANSACTIONS | ||||
| if (sckDivisor < SPI_CLOCK_DIV2 || sckDivisor > SPI_CLOCK_DIV256) { | |||||
| sckDivisor = SPI_CLOCK_DIV2; // may not be needed, testing. | |||||
| uint32_t br; // Baud rate control field in SPI_CR1. | |||||
| if (divisor <= 2) { | |||||
| br = SPI_CLOCK_DIV2; | |||||
| } else if (divisor <= 4) { | |||||
| br = SPI_CLOCK_DIV4; | |||||
| } else if (divisor <= 8) { | |||||
| br = SPI_CLOCK_DIV8; | |||||
| } else if (divisor <= 16) { | |||||
| br = SPI_CLOCK_DIV16; | |||||
| } else if (divisor <= 32) { | |||||
| br = SPI_CLOCK_DIV32; | |||||
| } else if (divisor <= 64) { | |||||
| br = SPI_CLOCK_DIV64; | |||||
| } else if (divisor <= 128) { | |||||
| br = SPI_CLOCK_DIV128; | |||||
| } else { | |||||
| br = SPI_CLOCK_DIV256; | |||||
| } | } | ||||
| SPI.setClockDivider(sckDivisor); | |||||
| SPI.setClockDivider(br); | |||||
| #if !ENABLE_SPI_TRANSACTIONS | |||||
| SPI.setBitOrder(MSBFIRST); | SPI.setBitOrder(MSBFIRST); | ||||
| SPI.setDataMode(SPI_MODE0); | SPI.setDataMode(SPI_MODE0); | ||||
| #if USE_STM32F1_DMAC | |||||
| dma_init(DMA1); | |||||
| dma_attach_interrupt(DMA1, SPI1_DMAC_TX_CH, SPI_DMA_TX_Event); | |||||
| dma_attach_interrupt(DMA1, SPI1_DMAC_RX_CH, SPI_DMA_RX_Event); | |||||
| spi_tx_dma_enable(SPI1); | |||||
| spi_rx_dma_enable(SPI1); | |||||
| #endif // USE_STM32F1_DMAC | |||||
| #endif // !ENABLE_SPI_TRANSACTIONS | |||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** | |||||
| * End SPI transaction. | |||||
| */ | |||||
| void SdSpi::endTransaction() { | void SdSpi::endTransaction() { | ||||
| #if ENABLE_SPI_TRANSACTIONS | #if ENABLE_SPI_TRANSACTIONS | ||||
| SPI.endTransaction(); | SPI.endTransaction(); | ||||
| #endif // ENABLE_SPI_TRANSACTIONS | #endif // ENABLE_SPI_TRANSACTIONS | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| // STM32 | |||||
| static inline uint8_t spiTransfer(uint8_t b) { | |||||
| return SPI.transfer(b); | |||||
| } | |||||
| //------------------------------------------------------------------------------ | |||||
| // should be valid for STM32 | |||||
| /** SPI receive a byte */ | |||||
| /** Receive a byte. | |||||
| * | |||||
| * \return The byte. | |||||
| */ | |||||
| uint8_t SdSpi::receive() { | uint8_t SdSpi::receive() { | ||||
| return spiTransfer(0xFF); | |||||
| return SPI.transfer(0XFF); | |||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** SPI receive multiple bytes */ | |||||
| // check and finish. | |||||
| /** Receive multiple bytes. | |||||
| * | |||||
| * \param[out] buf Buffer to receive the data. | |||||
| * \param[in] n Number of bytes to receive. | |||||
| * | |||||
| * \return Zero for no error or nonzero error code. | |||||
| */ | |||||
| uint8_t SdSpi::receive(uint8_t* buf, size_t n) { | uint8_t SdSpi::receive(uint8_t* buf, size_t n) { | ||||
| int rtn = 0; | int rtn = 0; | ||||
| #if USE_STM32F1_DMAC | #if USE_STM32F1_DMAC | ||||
| spiDmaRX(buf, n); | |||||
| spiDmaTX(0, n); | |||||
| uint32_t m = millis(); | |||||
| while (SPI_DMA_RX_Active) { | |||||
| if ((millis() - m) > STM32F1_DMA_TIMEOUT) { | |||||
| dmac_channel_disable(SPI_DMAC_RX_CH); | |||||
| dmac_channel_disable(SPI_DMAC_TX_CH); | |||||
| rtn = 2; | |||||
| break; | |||||
| } | |||||
| } | |||||
| rtn = SPI.dmaTransfer(0, const_cast<uint8*>(buf), n); | |||||
| #else // USE_STM32F1_DMAC | #else // USE_STM32F1_DMAC | ||||
| for (size_t i = 0; i < n; i++) { | |||||
| buf[i] = SPI.transfer(0xFF); | |||||
| } | |||||
| SPI.read(buf, n); | |||||
| #endif // USE_STM32F1_DMAC | #endif // USE_STM32F1_DMAC | ||||
| return rtn; | return rtn; | ||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** SPI send a byte */ | |||||
| /** Send a byte. | |||||
| * | |||||
| * \param[in] b Byte to send | |||||
| */ | |||||
| void SdSpi::send(uint8_t b) { | void SdSpi::send(uint8_t b) { | ||||
| spiTransfer(b); | |||||
| SPI.transfer(b); | |||||
| } | } | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** Send multiple bytes. | |||||
| * | |||||
| * \param[in] buf Buffer for data to be sent. | |||||
| * \param[in] n Number of bytes to send. | |||||
| */ | |||||
| void SdSpi::send(const uint8_t* buf , size_t n) { | void SdSpi::send(const uint8_t* buf , size_t n) { | ||||
| #if USE_STM32F1_DMAC | #if USE_STM32F1_DMAC | ||||
| spiDmaTX(buf, n); | |||||
| while (SPI_DMA_TX_Active) {} | |||||
| SPI.dmaSend(const_cast<uint8*>(buf), n); | |||||
| #else // #if USE_STM32F1_DMAC | #else // #if USE_STM32F1_DMAC | ||||
| SPI.write(buf, n); | SPI.write(buf, n); | ||||
| #endif // #if USE_STM32F1_DMAC | |||||
| // leave RX register empty | |||||
| // while (spi_is_rx_nonempty(SPI1)) | |||||
| uint8_t b = spi_rx_reg(SPI1); | |||||
| #endif // USE_STM32F1_DMAC | |||||
| } | } | ||||
| #endif // USE_NATIVE_STM32F1_SPI | #endif // USE_NATIVE_STM32F1_SPI |
| #define nop asm volatile ("nop\n\t") | #define nop asm volatile ("nop\n\t") | ||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** Pin Mode for MISO is input.*/ | /** Pin Mode for MISO is input.*/ | ||||
| const bool MISO_MODE = false; | |||||
| #define MISO_MODE INPUT | |||||
| /** Pullups disabled for MISO are disabled. */ | /** Pullups disabled for MISO are disabled. */ | ||||
| const bool MISO_LEVEL = false; | |||||
| #define MISO_LEVEL false | |||||
| /** Pin Mode for MOSI is output.*/ | /** Pin Mode for MOSI is output.*/ | ||||
| const bool MOSI_MODE = true; | |||||
| #define MOSI_MODE OUTPUT | |||||
| /** Pin Mode for SCK is output. */ | /** Pin Mode for SCK is output. */ | ||||
| const bool SCK_MODE = true; | |||||
| #define SCK_MODE OUTPUT | |||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||
| /** | /** | ||||
| * @class SoftSPI | * @class SoftSPI |