Compare commits
59 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8313193820 | ||
|
|
e72d81e8aa | ||
|
|
b11fcfdc59 | ||
|
|
7ec6995235 | ||
|
|
4537faa145 | ||
|
|
fb0d11a405 | ||
|
|
15c39defe5 | ||
|
|
3e298145ce | ||
|
|
5d752a3901 | ||
|
|
cf2a10a274 | ||
|
|
df91320ee6 | ||
|
|
476f8d979a | ||
|
|
8190df112f | ||
|
|
3f952664eb | ||
|
|
0f512b0155 | ||
|
|
ca1cf4e0e1 | ||
|
|
a13979b5ca | ||
|
|
4f3f65cb31 | ||
|
|
d3cbd6511c | ||
|
|
659033f387 | ||
|
|
367cde634d | ||
|
|
68dd2d4d80 | ||
|
|
54ca0c7012 | ||
|
|
850e1aaee1 | ||
|
|
b2a36980bb | ||
|
|
fa76619c03 | ||
|
|
56d6610432 | ||
|
|
cf8f5d8f61 | ||
|
|
28fd5dc4fc | ||
|
|
641f23b353 | ||
|
|
5d726947af | ||
|
|
94aad3094c | ||
|
|
f1f0f93432 | ||
|
|
d0a2565114 | ||
|
|
e157117f9c | ||
|
|
6324f8eed2 | ||
|
|
fca3f1475f | ||
|
|
1b0c9bce15 | ||
|
|
0b0f1296d3 | ||
|
|
81d38972f6 | ||
|
|
cb28106207 | ||
|
|
5de302b19a | ||
|
|
699c9e410e | ||
|
|
18f071dc69 | ||
|
|
31783e24e8 | ||
|
|
013b7ea281 | ||
|
|
829f4925f4 | ||
|
|
88902b576e | ||
|
|
f918ed0077 | ||
|
|
10cdd7964c | ||
|
|
ec247da5da | ||
|
|
f24364bff2 | ||
|
|
9c046af871 | ||
|
|
2b053a1910 | ||
|
|
7a8686d63d | ||
|
|
4d87dfbee3 | ||
|
|
391949068e | ||
|
|
98a88f0389 | ||
|
|
e0acc32b59 |
24 changed files with 431 additions and 28 deletions
92
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
92
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: Report a problem
|
||||||
|
labels: 'Bug'
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this bug report!
|
||||||
|
It's okay to leave some blank if it doesn't apply to your problem.
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: Operating System
|
||||||
|
options:
|
||||||
|
- Linux
|
||||||
|
- MacOS
|
||||||
|
- RaspberryPi OS
|
||||||
|
- Windows 7
|
||||||
|
- Windows 10
|
||||||
|
- Windows 11
|
||||||
|
- Others
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: IDE version
|
||||||
|
placeholder: e.g Arduino 1.8.15
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Board
|
||||||
|
placeholder: e.g Feather nRF52840 Express
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: BSP version
|
||||||
|
description: Can be found under "Board Manager" menu
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: SPIFlash Library version
|
||||||
|
placeholder: "Release version or github latest"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Sketch
|
||||||
|
placeholder: |
|
||||||
|
e.g examples/flash_info
|
||||||
|
If it is custom sketch, please provide links to your minimal sources or as attached files.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: What happened ?
|
||||||
|
placeholder: A clear and concise description of what the bug is.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: How to reproduce ?
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. See error
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Debug Log
|
||||||
|
placeholder: |
|
||||||
|
Debug log where the issue occurred as attached txt file, best with comments to explain the actual events.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If applicable, add screenshots to help explain your problem.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
contact_links:
|
||||||
|
- name: Adafruit Support Forum
|
||||||
|
url: https://forums.adafruit.com
|
||||||
|
about: If you have other questions or need help, post it here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: Feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
45
.github/workflows/githubci.yml
vendored
Normal file
45
.github/workflows/githubci.yml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
name: Build
|
||||||
|
|
||||||
|
on: [pull_request, push, repository_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
arduino-platform:
|
||||||
|
- 'feather_rp2040'
|
||||||
|
- 'metro_m0'
|
||||||
|
- 'metro_m4'
|
||||||
|
- 'nrf52840'
|
||||||
|
- 'metroesp32s2'
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Checkout adafruit/ci-arduino
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: adafruit/ci-arduino
|
||||||
|
path: ci
|
||||||
|
|
||||||
|
- name: pre-install
|
||||||
|
run: bash ci/actions_install.sh
|
||||||
|
|
||||||
|
- name: test platforms
|
||||||
|
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||||
|
|
||||||
|
#- name: clang
|
||||||
|
# skip clang for fatfs (ff) to make it easier to compare and upgrade
|
||||||
|
# run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -e "./examples/SdFat_format/*" -r .
|
||||||
|
|
||||||
|
#- name: doxygen
|
||||||
|
# env:
|
||||||
|
# GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
|
||||||
|
# PRETTYNAME : "Adafruit SPIFlash Library"
|
||||||
|
# run: bash ci/doxy_gen_and_deploy.sh
|
||||||
31
.travis.yml
Normal file
31
.travis.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
language: c
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- ~/arduino_ide
|
||||||
|
- ~/.arduino15/packages/
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: false
|
||||||
|
quiet: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- PRETTYNAME="SdFat (Adafruit Fork)"
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh)
|
||||||
|
|
||||||
|
install:
|
||||||
|
- git clone --quiet http://github.com/jrowberg/i2cdevlib.git $HOME/i2cdevlib
|
||||||
|
- mv $HOME/i2cdevlib/Arduino/* $HOME/Arduino/libraries/
|
||||||
|
- rm -rf $HOME/arduino_ide/libraries/Adafruit_Test_Library/examples/*attic
|
||||||
|
- rm -rf $HOME/arduino_ide/libraries/Adafruit_Test_Library/extras
|
||||||
|
|
||||||
|
script:
|
||||||
|
- build_main_platforms
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh)
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh)
|
||||||
0
examples/#attic/MiniSerial/.none.test.only
Normal file
0
examples/#attic/MiniSerial/.none.test.only
Normal file
0
examples/#attic/SD_Size/.feather_rp2040.test.skip
Normal file
0
examples/#attic/SD_Size/.feather_rp2040.test.skip
Normal file
0
examples/#attic/benchSD/.none.test.only
Normal file
0
examples/#attic/benchSD/.none.test.only
Normal file
0
examples/AnalogBinLogger/.none.test.only
Normal file
0
examples/AnalogBinLogger/.none.test.only
Normal file
0
examples/LowLatencyLogger/.none.test.only
Normal file
0
examples/LowLatencyLogger/.none.test.only
Normal file
0
examples/LowLatencyLoggerMPU6050/.none.test.only
Normal file
0
examples/LowLatencyLoggerMPU6050/.none.test.only
Normal file
|
|
@ -114,7 +114,7 @@ void loop() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
file.printField(12345678UL + i, '\n');
|
file.printField((uint32_t) (12345678UL + i), '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
|
|
|
||||||
0
examples/STM32Test/.none.test.only
Normal file
0
examples/STM32Test/.none.test.only
Normal file
0
examples/SoftwareSpi/.none.test.only
Normal file
0
examples/SoftwareSpi/.none.test.only
Normal file
0
examples/TeensySdioDemo/.none.test.only
Normal file
0
examples/TeensySdioDemo/.none.test.only
Normal file
|
|
@ -1,11 +1,12 @@
|
||||||
name=SdFat
|
name=SdFat - Adafruit Fork
|
||||||
version=1.1.0
|
version=1.5.1
|
||||||
license=MIT
|
license=MIT
|
||||||
author=Bill Greiman <fat16lib@sbcglobal.net>
|
author=Bill Greiman <fat16lib@sbcglobal.net>
|
||||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
|
maintainer=Adafruit <support@adafruit.com>
|
||||||
sentence=FAT16/FAT32 file system for SD cards.
|
sentence=FAT16/FAT32 file system for SD cards and QSPI Flash.
|
||||||
paragraph=FAT16/FAT32 file system for SD cards.
|
paragraph=FAT16/FAT32 file system for SD cards and QSPI Flash.
|
||||||
category=Data Storage
|
category=Data Storage
|
||||||
url=https://github.com/greiman/SdFat
|
url=https://github.com/adafruit/SdFat
|
||||||
repository=https://github.com/greiman/SdFat.git
|
repository=https://github.com/adafruit/SdFat.git
|
||||||
architectures=*
|
architectures=rp2040,nrf52,samd,esp32,*
|
||||||
|
depends=SD
|
||||||
|
|
|
||||||
|
|
@ -664,7 +664,7 @@ bool FatFile::openParent(FatFile* dirFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memset(&dotdot, 0, sizeof(FatFile));
|
memset((void*) &dotdot, 0, sizeof(FatFile));
|
||||||
dotdot.m_attr = FILE_ATTR_SUBDIR;
|
dotdot.m_attr = FILE_ATTR_SUBDIR;
|
||||||
dotdot.m_flags = F_READ;
|
dotdot.m_flags = F_READ;
|
||||||
dotdot.m_vol = dirFile->m_vol;
|
dotdot.m_vol = dirFile->m_vol;
|
||||||
|
|
@ -1215,7 +1215,14 @@ bool FatFile::sync() {
|
||||||
|
|
||||||
// set modify time if user supplied a callback date/time function
|
// set modify time if user supplied a callback date/time function
|
||||||
if (m_dateTime) {
|
if (m_dateTime) {
|
||||||
m_dateTime(&dir->lastWriteDate, &dir->lastWriteTime);
|
// use temp date/time to fix warning -Waddress-of-packed-member
|
||||||
|
uint16_t tmp_date = dir->lastWriteDate;
|
||||||
|
uint16_t tmp_time = dir->lastWriteTime;
|
||||||
|
|
||||||
|
m_dateTime(&tmp_date, &tmp_time);
|
||||||
|
|
||||||
|
dir->lastWriteDate = tmp_date;
|
||||||
|
dir->lastWriteTime = tmp_time;
|
||||||
dir->lastAccessDate = dir->lastWriteDate;
|
dir->lastAccessDate = dir->lastWriteDate;
|
||||||
}
|
}
|
||||||
// clear directory dirty
|
// clear directory dirty
|
||||||
|
|
|
||||||
|
|
@ -474,8 +474,15 @@ create:
|
||||||
|
|
||||||
// set timestamps
|
// set timestamps
|
||||||
if (m_dateTime) {
|
if (m_dateTime) {
|
||||||
|
// use temp date/time to fix warning -Waddress-of-packed-member
|
||||||
|
uint16_t tmp_date = dir->creationDate;
|
||||||
|
uint16_t tmp_time = dir->creationTime;
|
||||||
|
|
||||||
// call user date/time function
|
// call user date/time function
|
||||||
m_dateTime(&dir->creationDate, &dir->creationTime);
|
m_dateTime(&tmp_date, &tmp_time);
|
||||||
|
|
||||||
|
dir->creationDate = tmp_date;
|
||||||
|
dir->creationTime = tmp_time;
|
||||||
} else {
|
} else {
|
||||||
// use default date/time
|
// use default date/time
|
||||||
dir->creationDate = FAT_DEFAULT_DATE;
|
dir->creationDate = FAT_DEFAULT_DATE;
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ bool FatCache::sync() {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
// mirror second FAT
|
// mirror second FAT
|
||||||
if (m_status & CACHE_STATUS_MIRROR_FAT) {
|
if ( (m_vol->m_fatCount == 2) && (m_status & CACHE_STATUS_MIRROR_FAT) ) {
|
||||||
uint32_t lbn = m_lbn + m_vol->blocksPerFat();
|
uint32_t lbn = m_lbn + m_vol->blocksPerFat();
|
||||||
if (!m_vol->writeBlock(lbn, m_block.data)) {
|
if (!m_vol->writeBlock(lbn, m_block.data)) {
|
||||||
DBG_FAIL_MACRO;
|
DBG_FAIL_MACRO;
|
||||||
|
|
@ -487,12 +487,14 @@ bool FatVolume::init(uint8_t part) {
|
||||||
}
|
}
|
||||||
fbs = &(pc->fbs32);
|
fbs = &(pc->fbs32);
|
||||||
if (fbs->bytesPerSector != 512 ||
|
if (fbs->bytesPerSector != 512 ||
|
||||||
fbs->fatCount != 2 ||
|
fbs->fatCount < 1 ||
|
||||||
|
fbs->fatCount > 2 ||
|
||||||
fbs->reservedSectorCount == 0) {
|
fbs->reservedSectorCount == 0) {
|
||||||
// not valid FAT volume
|
// not valid FAT volume
|
||||||
DBG_FAIL_MACRO;
|
DBG_FAIL_MACRO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
m_fatCount = fbs->fatCount;
|
||||||
m_blocksPerCluster = fbs->sectorsPerCluster;
|
m_blocksPerCluster = fbs->sectorsPerCluster;
|
||||||
m_clusterBlockMask = m_blocksPerCluster - 1;
|
m_clusterBlockMask = m_blocksPerCluster - 1;
|
||||||
// determine shift that is same as multiply by m_blocksPerCluster
|
// determine shift that is same as multiply by m_blocksPerCluster
|
||||||
|
|
@ -512,7 +514,7 @@ bool FatVolume::init(uint8_t part) {
|
||||||
m_rootDirEntryCount = fbs->rootDirEntryCount;
|
m_rootDirEntryCount = fbs->rootDirEntryCount;
|
||||||
|
|
||||||
// directory start for FAT16 dataStart for FAT32
|
// directory start for FAT16 dataStart for FAT32
|
||||||
m_rootDirStart = m_fatStartBlock + 2 * m_blocksPerFat;
|
m_rootDirStart = m_fatStartBlock + m_fatCount * m_blocksPerFat;
|
||||||
// data start for FAT16 and FAT32
|
// data start for FAT16 and FAT32
|
||||||
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);
|
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);
|
||||||
|
|
||||||
|
|
@ -576,7 +578,7 @@ bool FatVolume::wipe(print_t* pr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear FATs.
|
// Clear FATs.
|
||||||
count = 2*m_blocksPerFat;
|
count = m_fatCount * m_blocksPerFat;
|
||||||
lbn = m_fatStartBlock;
|
lbn = m_fatStartBlock;
|
||||||
for (uint32_t nb = 0; nb < count; nb++) {
|
for (uint32_t nb = 0; nb < count; nb++) {
|
||||||
if (pr && (nb & 0XFF) == 0) {
|
if (pr && (nb & 0XFF) == 0) {
|
||||||
|
|
@ -601,7 +603,7 @@ bool FatVolume::wipe(print_t* pr) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (!writeBlock(m_fatStartBlock, cache->data) ||
|
if (!writeBlock(m_fatStartBlock, cache->data) ||
|
||||||
!writeBlock(m_fatStartBlock + m_blocksPerFat, cache->data)) {
|
(m_fatCount == 2 && !writeBlock(m_fatStartBlock + m_blocksPerFat, cache->data))) {
|
||||||
DBG_FAIL_MACRO;
|
DBG_FAIL_MACRO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,7 @@ class FatVolume {
|
||||||
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
|
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
|
||||||
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
|
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
|
||||||
uint8_t m_fatType; // Volume type (12, 16, OR 32).
|
uint8_t m_fatType; // Volume type (12, 16, OR 32).
|
||||||
|
uint8_t m_fatCount; // Number of FAT (1 or 2)
|
||||||
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
||||||
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||||
uint32_t m_blocksPerFat; // FAT size in blocks
|
uint32_t m_blocksPerFat; // FAT size in blocks
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
* These classes used extended multi-block SD I/O for better performance.
|
* These classes used extended multi-block SD I/O for better performance.
|
||||||
* the SPI bus may not be shared with other devices in this mode.
|
* the SPI bus may not be shared with other devices in this mode.
|
||||||
*/
|
*/
|
||||||
#define ENABLE_EXTENDED_TRANSFER_CLASS 0
|
#define ENABLE_EXTENDED_TRANSFER_CLASS 1
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* If the symbol USE_STANDARD_SPI_LIBRARY is zero, an optimized custom SPI
|
* If the symbol USE_STANDARD_SPI_LIBRARY is zero, an optimized custom SPI
|
||||||
|
|
@ -77,7 +77,9 @@
|
||||||
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the
|
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the
|
||||||
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort).
|
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort).
|
||||||
*/
|
*/
|
||||||
|
#ifndef USE_STANDARD_SPI_LIBRARY
|
||||||
#define USE_STANDARD_SPI_LIBRARY 0
|
#define USE_STANDARD_SPI_LIBRARY 0
|
||||||
|
#endif
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi
|
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi
|
||||||
|
|
@ -91,16 +93,16 @@
|
||||||
* will be defined by including the system file fcntl.h.
|
* will be defined by including the system file fcntl.h.
|
||||||
*/
|
*/
|
||||||
#if defined(__AVR__)
|
#if defined(__AVR__)
|
||||||
// AVR fcntl.h does not define open flags.
|
// AVR fcntl.h does not define open flags.
|
||||||
#define USE_FCNTL_H 0
|
#define USE_FCNTL_H 0
|
||||||
#elif defined(PLATFORM_ID)
|
#elif defined(PLATFORM_ID)
|
||||||
// Particle boards - use fcntl.h.
|
// Particle boards - use fcntl.h.
|
||||||
#define USE_FCNTL_H 1
|
#define USE_FCNTL_H 1
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__) || defined(ARDUINO_ARCH_ESP32)
|
||||||
// ARM gcc defines open flags.
|
// ARM and ESP32 gcc defines open flags.
|
||||||
#define USE_FCNTL_H 1
|
#define USE_FCNTL_H 1
|
||||||
#else // defined(__AVR__)
|
#else // defined(__AVR__)
|
||||||
#define USE_FCNTL_H 0
|
#define USE_FCNTL_H 0
|
||||||
#endif // defined(__AVR__)
|
#endif // defined(__AVR__)
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
|
|
@ -148,7 +150,7 @@
|
||||||
* Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
|
* Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
|
||||||
* FAT12 has not been well tested and requires additional flash.
|
* FAT12 has not been well tested and requires additional flash.
|
||||||
*/
|
*/
|
||||||
#define FAT12_SUPPORT 0
|
#define FAT12_SUPPORT 1
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
|
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
|
||||||
|
|
@ -209,7 +211,7 @@
|
||||||
/**
|
/**
|
||||||
* Determine the default SPI configuration.
|
* Determine the default SPI configuration.
|
||||||
*/
|
*/
|
||||||
#if defined(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID)
|
#if defined(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID) || defined(ARDUINO_ARCH_SAMD)
|
||||||
// has multiple SPI ports
|
// has multiple SPI ports
|
||||||
#define SD_HAS_CUSTOM_SPI 2
|
#define SD_HAS_CUSTOM_SPI 2
|
||||||
#elif defined(__AVR__)\
|
#elif defined(__AVR__)\
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,11 @@ typedef SdFatSpiDriver SdSpiDriver;
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
// Use of in-line for AVR to save flash.
|
// Use of in-line for AVR to save flash.
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
|
#if defined (__AVR_ATmega4809__)
|
||||||
|
#define SPDR SPI0_DATA
|
||||||
|
#define SPSR SPI0_INTFLAGS
|
||||||
|
#define SPIF 7
|
||||||
|
#endif // __AVR_ATmega4809__
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
inline void SdSpiAltDriver::begin(uint8_t csPin) {
|
inline void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
m_csPin = csPin;
|
m_csPin = csPin;
|
||||||
|
|
|
||||||
186
src/SpiDriver/SdSpiSAMD.cpp
Normal file
186
src/SpiDriver/SdSpiSAMD.cpp
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(ARDUINO_ARCH_SAMD)
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
/** Use Adafruit_ZeroDMA library if nonzero */
|
||||||
|
#define USE_SAMD_DMA_RECV 0
|
||||||
|
#define USE_SAMD_DMA_SEND 0
|
||||||
|
|
||||||
|
#if USE_SAMD_DMA_RECV || USE_SAMD_DMA_SEND
|
||||||
|
#include <Adafruit_ZeroDMA.h>
|
||||||
|
#include "utility/dma.h"
|
||||||
|
// Three DMA channels are used. SPI DMA read requires two channels,
|
||||||
|
// one for the "dummy writes" to initiate SPI transfers, the other
|
||||||
|
// to read each incoming byte. Write requires only one channel, and
|
||||||
|
// there's probably ways to "recycle" the first of the read channels,
|
||||||
|
// but that'll take some work and is not done here, have plenty of
|
||||||
|
// channels to go around. Each channel uses one descriptor.
|
||||||
|
#define CHANNEL_READ_TX 0
|
||||||
|
#define CHANNEL_READ_RX 1
|
||||||
|
#define CHANNEL_WRITE 2
|
||||||
|
static Adafruit_ZeroDMA DMAchannel[3];
|
||||||
|
static DmacDescriptor *channelDescriptor[3];
|
||||||
|
static volatile bool dma_busy = false;
|
||||||
|
static uint8_t dum = 0xFF; // Nonsense for SPI transfer init
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Transfer-complete callback for Adafruit_ZeroDMA library.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void dma_callback(Adafruit_ZeroDMA *dma) {
|
||||||
|
dma_busy = false;
|
||||||
|
}
|
||||||
|
#endif // end USE_SAMD_DMA
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set SPI options for access to SD/SDHC cards.
|
||||||
|
*
|
||||||
|
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
m_spi->beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] chipSelectPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
m_spi->begin();
|
||||||
|
|
||||||
|
#if USE_SAMD_DMA_RECV || USE_SAMD_DMA_SEND
|
||||||
|
|
||||||
|
// First channel and descriptor are for SPI read "dummy writes" (TX)
|
||||||
|
DMAchannel[CHANNEL_READ_TX].allocate(); // Allocate DMA channel
|
||||||
|
channelDescriptor[CHANNEL_READ_TX] =
|
||||||
|
DMAchannel[CHANNEL_READ_TX].addDescriptor(
|
||||||
|
(void *)&dum, // Source address (nonsense)
|
||||||
|
(void *)m_spi->getDataRegister(), // Dest
|
||||||
|
0, // Count (0 for now, set later)
|
||||||
|
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
|
||||||
|
false, // Don't increment source address
|
||||||
|
false); // Don't increment dest address
|
||||||
|
DMAchannel[CHANNEL_READ_TX].setTrigger(m_spi->getDMAC_ID_TX());
|
||||||
|
DMAchannel[CHANNEL_READ_TX].setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
|
DMAchannel[CHANNEL_READ_TX].setCallback(dma_callback);
|
||||||
|
|
||||||
|
// Second channel and descriptor are for actual SPI read (RX)
|
||||||
|
DMAchannel[CHANNEL_READ_RX].allocate(); // Allocate DMA channel
|
||||||
|
channelDescriptor[CHANNEL_READ_RX] =
|
||||||
|
DMAchannel[CHANNEL_READ_RX].addDescriptor(
|
||||||
|
(void *)m_spi->getDataRegister(), // Source address
|
||||||
|
NULL, // Dest address (NULL for now, set later)
|
||||||
|
0, // Count (0 for now, set later)
|
||||||
|
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
|
||||||
|
false, // Don't increment source address
|
||||||
|
true); // Increment dest address
|
||||||
|
DMAchannel[CHANNEL_READ_RX].setTrigger(m_spi->getDMAC_ID_RX());
|
||||||
|
DMAchannel[CHANNEL_READ_RX].setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
|
DMAchannel[CHANNEL_READ_RX].setCallback(dma_callback);
|
||||||
|
|
||||||
|
// SPI write is its own channel and descriptor
|
||||||
|
DMAchannel[CHANNEL_WRITE].allocate(); // Allocate DMA channel
|
||||||
|
channelDescriptor[CHANNEL_WRITE] =
|
||||||
|
DMAchannel[CHANNEL_WRITE].addDescriptor(
|
||||||
|
NULL, // Src address (NULL for now, set later)
|
||||||
|
(void *)m_spi->getDataRegister(), // Dest address
|
||||||
|
0, // Count (0 for now, set later)
|
||||||
|
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
|
||||||
|
true, // Increment source address
|
||||||
|
false); // Don't increment dest address
|
||||||
|
DMAchannel[CHANNEL_WRITE].setTrigger(m_spi->getDMAC_ID_TX());
|
||||||
|
DMAchannel[CHANNEL_WRITE].setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
|
DMAchannel[CHANNEL_WRITE].setCallback(dma_callback);
|
||||||
|
#endif // USE_SAMD_DMA
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* End SPI transaction.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
m_spi->endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return m_spi->transfer(0XFF);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** 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 SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
#if USE_SAMD_DMA_RECV
|
||||||
|
// Configure the SPI read "dummy write" (TX) length (n)
|
||||||
|
DMAchannel[CHANNEL_READ_TX].changeDescriptor(
|
||||||
|
channelDescriptor[CHANNEL_READ_TX], NULL, NULL, n);
|
||||||
|
|
||||||
|
// Configure the SPI read (RX) length (n) into buf
|
||||||
|
DMAchannel[CHANNEL_READ_RX].changeDescriptor(
|
||||||
|
channelDescriptor[CHANNEL_READ_RX], NULL, (void *)buf, n);
|
||||||
|
|
||||||
|
dma_busy = true;
|
||||||
|
DMAchannel[CHANNEL_READ_RX].startJob(); // Start the RX job BEFORE the
|
||||||
|
DMAchannel[CHANNEL_READ_TX].startJob(); // TX job! That's the secret sauce.
|
||||||
|
while(dma_busy);
|
||||||
|
#else // USE_SAMD_DMA_RECV
|
||||||
|
while(n--) *buf++ = m_spi->transfer(0xFF);
|
||||||
|
#endif // USE_SAMD_DMA_RECV
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] b Byte to send
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
m_spi->transfer(b);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
#if USE_SAMD_DMA_SEND
|
||||||
|
DMAchannel[CHANNEL_WRITE].changeDescriptor(
|
||||||
|
channelDescriptor[CHANNEL_WRITE], (void *)buf, NULL, n);
|
||||||
|
dma_busy = true;
|
||||||
|
DMAchannel[CHANNEL_WRITE].startJob();
|
||||||
|
while(dma_busy);
|
||||||
|
#else // USE_SAMD_DMA_SEND
|
||||||
|
while(n--) m_spi->transfer(*buf++);
|
||||||
|
#endif // USE_SAMD_DMA_SEND
|
||||||
|
}
|
||||||
|
#endif // defined(ARDUINO_ARCH_SAMD)
|
||||||
Loading…
Reference in a new issue