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;
|
||||
|
||||
case 3:
|
||||
file.printField(12345678UL + i, '\n');
|
||||
file.printField((uint32_t) (12345678UL + i), '\n');
|
||||
break;
|
||||
|
||||
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
|
||||
version=1.1.0
|
||||
name=SdFat - Adafruit Fork
|
||||
version=1.5.1
|
||||
license=MIT
|
||||
author=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
sentence=FAT16/FAT32 file system for SD cards.
|
||||
paragraph=FAT16/FAT32 file system for SD cards.
|
||||
maintainer=Adafruit <support@adafruit.com>
|
||||
sentence=FAT16/FAT32 file system for SD cards and QSPI Flash.
|
||||
paragraph=FAT16/FAT32 file system for SD cards and QSPI Flash.
|
||||
category=Data Storage
|
||||
url=https://github.com/greiman/SdFat
|
||||
repository=https://github.com/greiman/SdFat.git
|
||||
architectures=*
|
||||
url=https://github.com/adafruit/SdFat
|
||||
repository=https://github.com/adafruit/SdFat.git
|
||||
architectures=rp2040,nrf52,samd,esp32,*
|
||||
depends=SD
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ bool FatFile::openParent(FatFile* dirFile) {
|
|||
goto fail;
|
||||
}
|
||||
} else {
|
||||
memset(&dotdot, 0, sizeof(FatFile));
|
||||
memset((void*) &dotdot, 0, sizeof(FatFile));
|
||||
dotdot.m_attr = FILE_ATTR_SUBDIR;
|
||||
dotdot.m_flags = F_READ;
|
||||
dotdot.m_vol = dirFile->m_vol;
|
||||
|
|
@ -1215,7 +1215,14 @@ bool FatFile::sync() {
|
|||
|
||||
// set modify time if user supplied a callback date/time function
|
||||
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;
|
||||
}
|
||||
// clear directory dirty
|
||||
|
|
|
|||
|
|
@ -474,8 +474,15 @@ create:
|
|||
|
||||
// set timestamps
|
||||
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
|
||||
m_dateTime(&dir->creationDate, &dir->creationTime);
|
||||
m_dateTime(&tmp_date, &tmp_time);
|
||||
|
||||
dir->creationDate = tmp_date;
|
||||
dir->creationTime = tmp_time;
|
||||
} else {
|
||||
// use default date/time
|
||||
dir->creationDate = FAT_DEFAULT_DATE;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ bool FatCache::sync() {
|
|||
goto fail;
|
||||
}
|
||||
// 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();
|
||||
if (!m_vol->writeBlock(lbn, m_block.data)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -487,12 +487,14 @@ bool FatVolume::init(uint8_t part) {
|
|||
}
|
||||
fbs = &(pc->fbs32);
|
||||
if (fbs->bytesPerSector != 512 ||
|
||||
fbs->fatCount != 2 ||
|
||||
fbs->fatCount < 1 ||
|
||||
fbs->fatCount > 2 ||
|
||||
fbs->reservedSectorCount == 0) {
|
||||
// not valid FAT volume
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
m_fatCount = fbs->fatCount;
|
||||
m_blocksPerCluster = fbs->sectorsPerCluster;
|
||||
m_clusterBlockMask = m_blocksPerCluster - 1;
|
||||
// determine shift that is same as multiply by m_blocksPerCluster
|
||||
|
|
@ -512,7 +514,7 @@ bool FatVolume::init(uint8_t part) {
|
|||
m_rootDirEntryCount = fbs->rootDirEntryCount;
|
||||
|
||||
// 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
|
||||
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);
|
||||
|
||||
|
|
@ -576,7 +578,7 @@ bool FatVolume::wipe(print_t* pr) {
|
|||
}
|
||||
}
|
||||
// Clear FATs.
|
||||
count = 2*m_blocksPerFat;
|
||||
count = m_fatCount * m_blocksPerFat;
|
||||
lbn = m_fatStartBlock;
|
||||
for (uint32_t nb = 0; nb < count; nb++) {
|
||||
if (pr && (nb & 0XFF) == 0) {
|
||||
|
|
@ -601,7 +603,7 @@ bool FatVolume::wipe(print_t* pr) {
|
|||
goto fail;
|
||||
}
|
||||
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;
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ class FatVolume {
|
|||
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
|
||||
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
|
||||
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.
|
||||
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||
uint32_t m_blocksPerFat; // FAT size in blocks
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
* 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.
|
||||
*/
|
||||
#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
|
||||
|
|
@ -77,7 +77,9 @@
|
|||
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the
|
||||
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort).
|
||||
*/
|
||||
#ifndef USE_STANDARD_SPI_LIBRARY
|
||||
#define USE_STANDARD_SPI_LIBRARY 0
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
#if defined(__AVR__)
|
||||
// AVR fcntl.h does not define open flags.
|
||||
#define USE_FCNTL_H 0
|
||||
// AVR fcntl.h does not define open flags.
|
||||
#define USE_FCNTL_H 0
|
||||
#elif defined(PLATFORM_ID)
|
||||
// Particle boards - use fcntl.h.
|
||||
#define USE_FCNTL_H 1
|
||||
#elif defined(__arm__)
|
||||
// ARM gcc defines open flags.
|
||||
#define USE_FCNTL_H 1
|
||||
// Particle boards - use fcntl.h.
|
||||
#define USE_FCNTL_H 1
|
||||
#elif defined(__arm__) || defined(ARDUINO_ARCH_ESP32)
|
||||
// ARM and ESP32 gcc defines open flags.
|
||||
#define USE_FCNTL_H 1
|
||||
#else // defined(__AVR__)
|
||||
#define USE_FCNTL_H 0
|
||||
#define USE_FCNTL_H 0
|
||||
#endif // defined(__AVR__)
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
|
|
@ -148,7 +150,7 @@
|
|||
* Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
|
||||
* 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.
|
||||
|
|
@ -209,7 +211,7 @@
|
|||
/**
|
||||
* 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
|
||||
#define SD_HAS_CUSTOM_SPI 2
|
||||
#elif defined(__AVR__)\
|
||||
|
|
|
|||
|
|
@ -372,6 +372,11 @@ typedef SdFatSpiDriver SdSpiDriver;
|
|||
//==============================================================================
|
||||
// Use of in-line for AVR to save flash.
|
||||
#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) {
|
||||
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