Skip to content

Commit 6656dd2

Browse files
authored
Merge pull request #39 from Marzogh/SPI-Transactions-w.i.p
v2.5.0-final
2 parents a804cdd + 2d2b524 commit 6656dd2

17 files changed

Lines changed: 1590 additions & 867 deletions

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ before_install:
55
script:
66
#- build_main_platforms
77
- build_platform uno
8-
- build_platform leonardo
8+
- build_platform due
99
#- build_platform zero
1010
- build_platform esp8266
11+
- build_platform leonardo
1112
- build_platform mega
1213
- build_platform fio
1314
- build_platform micro
14-
- build_platform due
1515
notifications:
1616
email:
1717
on_success: change

Changes.log renamed to Changelog.md

Lines changed: 157 additions & 127 deletions
Large diffs are not rendered by default.

DMASPI.cpp

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
/* Arduino SPIFlash Library v.2.5.0
2+
* Copyright (C) 2015 by Prajwal Bhattaram
3+
* Modified by Prajwal Bhattaram - 30/09/2016
4+
*
5+
* This file is part of the Arduino SPIFlash Library. This library is for
6+
* Winbond NOR flash memory modules. In its current form it enables reading
7+
* and writing individual data variables, structs and arrays from and to various locations;
8+
* reading and writing pages; continuous read functions; sector, block and chip erase;
9+
* suspending and resuming programming/erase and powering down for low power operation.
10+
*
11+
* This Library is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* This Library is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU General Public License v3.0
22+
* along with the Arduino SPIFlash Library. If not, see
23+
* <http://www.gnu.org/licenses/>.
24+
*/
25+
#if defined (ARDUINO_ARCH_SAM)
26+
#include "SPIFlash.h"
27+
28+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
29+
// Private functions used by Arduino Due DMA operations //
30+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
31+
// Disable DMA Controller
32+
void SPIFlash::_dmac_disable() {
33+
DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
34+
}
35+
// Enable DMA Controller.
36+
void SPIFlash::_dmac_enable() {
37+
DMAC->DMAC_EN = DMAC_EN_ENABLE;
38+
}
39+
// Disable DMA Channel
40+
void SPIFlash::_dmac_channel_disable(uint32_t ul_num) {
41+
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
42+
}
43+
// Enable DMA Channel
44+
void SPIFlash::_dmac_channel_enable(uint32_t ul_num) {
45+
DMAC->DMAC_CHER = DMAC_CHER_ENA0 << ul_num;
46+
}
47+
// Poll for transfer complete
48+
bool SPIFlash::_dmac_channel_transfer_done(uint32_t ul_num) {
49+
return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
50+
}
51+
// start RX DMA
52+
void SPIFlash::_dueSPIDmaRX(uint8_t* dst, uint16_t count) {
53+
_dmac_channel_disable(SPI_DMAC_RX_CH);
54+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
55+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
56+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
57+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
58+
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
59+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
60+
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
61+
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
62+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
63+
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
64+
_dmac_channel_enable(SPI_DMAC_RX_CH);
65+
}
66+
void SPIFlash::_dueSPIDmaRX(char* dst, uint16_t count) {
67+
_dmac_channel_disable(SPI_DMAC_RX_CH);
68+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
69+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
70+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
71+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
72+
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
73+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
74+
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
75+
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
76+
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
77+
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
78+
_dmac_channel_enable(SPI_DMAC_RX_CH);
79+
}
80+
// start TX DMA
81+
void SPIFlash::_dueSPIDmaTX(const uint8_t* src, uint16_t count) {
82+
static uint8_t ff = 0XFF;
83+
uint32_t src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING;
84+
if (!src) {
85+
src = &ff;
86+
src_incr = DMAC_CTRLB_SRC_INCR_FIXED;
87+
}
88+
_dmac_channel_disable(SPI_DMAC_TX_CH);
89+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
90+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
91+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
92+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
93+
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
94+
95+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
96+
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
97+
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
98+
99+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
100+
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
101+
102+
_dmac_channel_enable(SPI_DMAC_TX_CH);
103+
}
104+
105+
void SPIFlash::_dueSPIDmaCharTX(const char* src, uint16_t count) {
106+
static char ff = 0XFF;
107+
uint32_t src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING;
108+
if (!src) {
109+
src = &ff;
110+
src_incr = DMAC_CTRLB_SRC_INCR_FIXED;
111+
}
112+
_dmac_channel_disable(SPI_DMAC_TX_CH);
113+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
114+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
115+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
116+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
117+
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
118+
119+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
120+
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
121+
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
122+
123+
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
124+
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
125+
126+
_dmac_channel_enable(SPI_DMAC_TX_CH);
127+
}
128+
129+
void SPIFlash::_dueSPIBegin() {
130+
PIO_Configure(
131+
g_APinDescription[PIN_SPI_MOSI].pPort,
132+
g_APinDescription[PIN_SPI_MOSI].ulPinType,
133+
g_APinDescription[PIN_SPI_MOSI].ulPin,
134+
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
135+
PIO_Configure(
136+
g_APinDescription[PIN_SPI_MISO].pPort,
137+
g_APinDescription[PIN_SPI_MISO].ulPinType,
138+
g_APinDescription[PIN_SPI_MISO].ulPin,
139+
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
140+
PIO_Configure(
141+
g_APinDescription[PIN_SPI_SCK].pPort,
142+
g_APinDescription[PIN_SPI_SCK].ulPinType,
143+
g_APinDescription[PIN_SPI_SCK].ulPin,
144+
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
145+
pmc_enable_periph_clk(ID_SPI0);
146+
#if USE_SAM3X_DMAC
147+
pmc_enable_periph_clk(ID_DMAC);
148+
_dmac_disable();
149+
DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED;
150+
_dmac_enable();
151+
#if USE_SAM3X_BUS_MATRIX_FIX
152+
MATRIX->MATRIX_WPMR = 0x4d415400;
153+
MATRIX->MATRIX_MCFG[1] = 1;
154+
MATRIX->MATRIX_MCFG[2] = 1;
155+
MATRIX->MATRIX_SCFG[0] = 0x01000010;
156+
MATRIX->MATRIX_SCFG[1] = 0x01000010;
157+
MATRIX->MATRIX_SCFG[7] = 0x01000010;
158+
#endif // USE_SAM3X_BUS_MATRIX_FIX
159+
#endif // USE_SAM3X_DMAC
160+
}
161+
// initialize SPI controller
162+
void SPIFlash::_dueSPIInit(uint8_t dueSckDivisor) {
163+
#if ENABLE_SPI_TRANSACTIONS
164+
SPI.beginTransaction(SPISettings());
165+
#endif // ENABLE_SPI_TRANSACTIONS
166+
uint8_t scbr = dueSckDivisor;
167+
Spi* pSpi = SPI0;
168+
// disable SPI
169+
pSpi->SPI_CR = SPI_CR_SPIDIS;
170+
// reset SPI
171+
pSpi->SPI_CR = SPI_CR_SWRST;
172+
// no mode fault detection, set master mode
173+
pSpi->SPI_MR = SPI_PCS(SPI_CHIP_SEL) | SPI_MR_MODFDIS | SPI_MR_MSTR;
174+
// mode 0, 8-bit,
175+
pSpi->SPI_CSR[SPI_CHIP_SEL] = SPI_CSR_SCBR(scbr) | SPI_CSR_NCPHA;
176+
// enable SPI
177+
pSpi->SPI_CR |= SPI_CR_SPIEN;
178+
}
179+
uint8_t SPIFlash::_dueSPITransfer(uint8_t b) {
180+
Spi* pSpi = SPI0;
181+
182+
pSpi->SPI_TDR = b;
183+
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
184+
b = pSpi->SPI_RDR;
185+
return b;
186+
}
187+
// SPI receive a byte
188+
uint8_t SPIFlash::_dueSPIRecByte() {
189+
return _dueSPITransfer(0XFF);
190+
}
191+
// SPI receive multiple bytes
192+
uint8_t SPIFlash::_dueSPIRecByte(uint8_t* buf, size_t len) {
193+
Spi* pSpi = SPI0;
194+
int rtn = 0;
195+
#if USE_SAM3X_DMAC
196+
// clear overrun error
197+
uint32_t s = pSpi->SPI_SR;
198+
199+
_dueSPIDmaRX(buf, len);
200+
_dueSPIDmaTX(0, len);
201+
202+
uint32_t m = millis();
203+
while (!_dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
204+
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
205+
_dmac_channel_disable(SPI_DMAC_RX_CH);
206+
_dmac_channel_disable(SPI_DMAC_TX_CH);
207+
rtn = 2;
208+
break;
209+
}
210+
}
211+
if (pSpi->SPI_SR & SPI_SR_OVRES) rtn |= 1;
212+
#else // USE_SAM3X_DMAC
213+
for (size_t i = 0; i < len; i++) {
214+
pSpi->SPI_TDR = 0XFF;
215+
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
216+
buf[i] = pSpi->SPI_RDR;
217+
}
218+
#endif // USE_SAM3X_DMAC
219+
return rtn;
220+
}
221+
// SPI receive a char
222+
int8_t SPIFlash::_dueSPIRecChar() {
223+
return _dueSPITransfer(0XFF);
224+
}
225+
// SPI receive multiple chars
226+
int8_t SPIFlash::_dueSPIRecChar(char* buf, size_t len) {
227+
Spi* pSpi = SPI0;
228+
char rtn = 0;
229+
#if USE_SAM3X_DMAC
230+
// clear overrun error
231+
uint32_t s = pSpi->SPI_SR;
232+
233+
_dueSPIDmaRX(buf, len);
234+
_dueSPIDmaTX(0, len);
235+
236+
uint32_t m = millis();
237+
while (!_dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
238+
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
239+
_dmac_channel_disable(SPI_DMAC_RX_CH);
240+
_dmac_channel_disable(SPI_DMAC_TX_CH);
241+
rtn = 2;
242+
break;
243+
}
244+
}
245+
if (pSpi->SPI_SR & SPI_SR_OVRES) rtn |= 1;
246+
#else // USE_SAM3X_DMAC
247+
for (size_t i = 0; i < len; i++) {
248+
pSpi->SPI_TDR = 0XFF;
249+
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
250+
buf[i] = pSpi->SPI_RDR;
251+
}
252+
#endif // USE_SAM3X_DMAC
253+
return rtn;
254+
}
255+
// SPI send a byte
256+
void SPIFlash::_dueSPISendByte(uint8_t b) {
257+
_dueSPITransfer(b);
258+
}
259+
260+
void SPIFlash::_dueSPISendByte(const uint8_t* buf, size_t len) {
261+
Spi* pSpi = SPI0;
262+
#if USE_SAM3X_DMAC
263+
_dueSPIDmaTX(buf, len);
264+
while (!_dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
265+
#else // #if USE_SAM3X_DMAC
266+
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
267+
for (size_t i = 0; i < len; i++) {
268+
pSpi->SPI_TDR = buf[i];
269+
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
270+
}
271+
#endif // #if USE_SAM3X_DMAC
272+
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
273+
// leave RDR empty
274+
uint8_t b = pSpi->SPI_RDR;
275+
}
276+
// SPI send a char
277+
void SPIFlash::_dueSPISendChar(char b) {
278+
_dueSPITransfer(b);
279+
}
280+
//SPI send multiple chars
281+
void SPIFlash::_dueSPISendChar(const char* buf, size_t len) {
282+
Spi* pSpi = SPI0;
283+
#if USE_SAM3X_DMAC
284+
_dueSPIDmaCharTX(buf, len);
285+
while (!_dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
286+
#else // #if USE_SAM3X_DMAC
287+
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
288+
for (size_t i = 0; i < len; i++) {
289+
pSpi->SPI_TDR = buf[i];
290+
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
291+
}
292+
#endif // #if USE_SAM3X_DMAC
293+
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
294+
// leave RDR empty
295+
char b = pSpi->SPI_RDR;
296+
}
297+
298+
#endif

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=master)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash)
33
### Arduino library for Winbond Flash Memory Chips
4-
<sup> Download the latest stable release (v2.4.0) from <a href = "https://github.com/Marzogh/SPIFlash/releases/latest">here</a>. Please report any bugs in issues.</sup>
4+
<sup> Download the latest stable release (v2.5.0) from <a href = "https://github.com/Marzogh/SPIFlash/releases/latest">here</a>. Please report any bugs in issues.</sup>
55

66
This Arduino library is for use with Winbond serial flash memory chips. In its current form it supports identifying the flash chip and its various features; automatic address allocation and management; reading and writing bytes/chars/ints/longs/floats/Strings from and to various locations; reading and writing pages of bytes; continous reading/writing of data from/to arrays of bytes/chars; sector, block and chip erase; and powering down for low power operation.
77

@@ -11,7 +11,7 @@ This Arduino library is for use with Winbond serial flash memory chips. In its c
1111
#####Arduino IDEs supported
1212
- IDE v1.5.x
1313
- IDE v1.6.0-v1.6.5
14-
- IDE v1.6.9-v1.6.11
14+
- IDE v1.6.9-v1.6.12
1515

1616
#####Boards
1717

@@ -53,6 +53,8 @@ The library enables the following functions:
5353
##### Primary commands
5454
###### begin()
5555
Must be called at the start in setup(). This function detects the type of chip being used and sets parameters accordingly.
56+
###### setClock(clockSpeed)
57+
Must be called straight after begin(). This function takes a 32-bit number as replacement for the default maximum clock speed (104MHz for Winbond NOR flash) thereby initiating future SPI transactions with the user-defined clock speed. Use with care.
5658
###### error()
5759
Returns the (8-bit) error code generated by the function called immediately before this is called. Refer to the [Error codes & Error reporting] (https://github.com/Marzogh/SPIFlash/wiki/Error-codes-&-Error-reporting) section the Wiki for further reference.
5860
###### getMANID()
@@ -204,5 +206,3 @@ Reads all pages on Flash chip and dumps it to Serial stream. This function is us
204206
- Then type the command to read all pages into the Serial console. If you use my code from the example file the command is ```read_all_pages```
205207
- Wait a few seconds before typing ```Ctrl+C``` to end the tail process
206208
- Check that you have actually recieved all the data by typing ```% cat FlashDump.txt```. This should output the entire textfile into your terminal window.
207-
208-
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Marzogh/spiflash/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

0 commit comments

Comments
 (0)