#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 |