-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Spi0command #6674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Spi0command #6674
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
71d348c
precache() - preload code into the flash cache.
ChocolateFrogsNuts acde951
Fix missing include
ChocolateFrogsNuts 482310d
Merge branch 'master' into precache
ChocolateFrogsNuts e74736c
Make precache extern "C"
ChocolateFrogsNuts fdbe442
Merge branch 'precache' of https://github.com/ChocolateFrogsNuts/Ardu…
ChocolateFrogsNuts 2cbdb41
Attempt 2 at making precache extern "C"
ChocolateFrogsNuts 0a7862a
Fix calculation of number of cache lines to preload
ChocolateFrogsNuts 8e4f9d0
SPI0Command - A utility function for generic SPI commands on SPI0
ChocolateFrogsNuts e2c6505
Clean some trailing spaces
ChocolateFrogsNuts d9d07cb
Upgrade _SPI0Command to _SPICommand
ChocolateFrogsNuts 34084e9
Tidy up a comment thats no longer applicable
ChocolateFrogsNuts adadaeb
Merge branch 'master' into spi0command
ChocolateFrogsNuts a2d1400
Merge branch 'master' into spi0command
ChocolateFrogsNuts 63cbbf7
Comments, formatting and variable renames
ChocolateFrogsNuts abcb709
put SPI0Command in namespace experimental
ChocolateFrogsNuts 7b2710c
Add a comment noting that the code has only been tested on bus 0
ChocolateFrogsNuts 78af7d9
Merge branch 'master' into spi0command
devyte 97ce07c
Replace use of memcpy with for loops in _SPICommand()
ChocolateFrogsNuts 0890556
Merge branch 'master' into spi0command
ChocolateFrogsNuts a40577c
Typo fix
ChocolateFrogsNuts 55b3a59
Merge branch 'spi0command' of https://github.com/ChocolateFrogsNuts/A…
ChocolateFrogsNuts 71a14a4
Merge branch 'master' into spi0command
ChocolateFrogsNuts 2d7c43b
Move the SpiOpResult enum into experimental namespace
ChocolateFrogsNuts File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
core_esp8266_spi_utils.cpp | ||
|
||
Copyright (c) 2019 Mike Nix. All rights reserved. | ||
This file is part of the esp8266 core for Arduino environment. | ||
|
||
This library is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
License as published by the Free Software Foundation; either | ||
version 2.1 of the License, or (at your option) any later version. | ||
|
||
This library is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
Lesser General Public License for more details. | ||
|
||
You should have received a copy of the GNU Lesser General Public | ||
License along with this library; if not, write to the Free Software | ||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
*/ | ||
|
||
#include <stdint.h> | ||
#include <string.h> | ||
|
||
// register names | ||
#include "esp8266_peri.h" | ||
|
||
// for flashchip | ||
#include "spi_flash.h" | ||
|
||
// for PRECACHE_* | ||
#include "core_esp8266_features.h" | ||
|
||
#include "spi_utils.h" | ||
|
||
extern "C" uint32_t Wait_SPI_Idle(SpiFlashChip *fc); | ||
|
||
namespace experimental { | ||
|
||
/* | ||
* critical part of SPICommand. | ||
* Kept in a separate function to aid with precaching | ||
* PRECACHE_* saves having to make the function IRAM_ATTR. | ||
* | ||
* spiIfNum needs to be volatile to keep the optimiser from | ||
* deciding it can be treated as a constant (due to this being a | ||
* static function only called with spiIfNum set to 0) | ||
* | ||
* Note: if porting to ESP32 mosi/miso bits are set in 2 registers, not 1. | ||
*/ | ||
static SpiOpResult PRECACHE_ATTR | ||
_SPICommand(volatile uint32_t spiIfNum, | ||
uint32_t spic,uint32_t spiu,uint32_t spiu1,uint32_t spiu2, | ||
uint32_t *data,uint32_t writeWords,uint32_t readWords) | ||
{ | ||
if (spiIfNum>1) | ||
return SPI_RESULT_ERR; | ||
|
||
// force SPI register access via base+offest. | ||
// Prevents loading individual address constants from flash. | ||
uint32_t *spibase = (uint32_t*)(spiIfNum ? &(SPI1CMD) : &(SPI0CMD)); | ||
devyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#define SPIREG(reg) (*((volatile uint32_t *)(spibase+(&(reg) - &(SPI0CMD))))) | ||
|
||
// preload any constants and functions we need into variables | ||
// Everything defined here must be volatile or the optimizer can | ||
// treat them as constants, resulting in the flash reads we're | ||
// trying to avoid | ||
uint32_t (* volatile Wait_SPI_Idlep)(SpiFlashChip *) = Wait_SPI_Idle; | ||
devyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
volatile SpiFlashChip *fchip=flashchip; | ||
volatile uint32_t spicmdusr=SPICMDUSR; | ||
|
||
if (!spiIfNum) { | ||
// Only need to precache when using SPI0 | ||
PRECACHE_START(); | ||
devyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Wait_SPI_Idlep((SpiFlashChip *)fchip); | ||
} | ||
|
||
// preserve essential controller state such as incoming/outgoing | ||
// data lengths and IO mode. | ||
uint32_t oldSPI0U = SPIREG(SPI0U); | ||
uint32_t oldSPI0U2= SPIREG(SPI0U2); | ||
uint32_t oldSPI0C = SPIREG(SPI0C); | ||
|
||
//SPI0S &= ~(SPISE|SPISBE|SPISSE|SPISCD); | ||
SPIREG(SPI0C) = spic; | ||
SPIREG(SPI0U) = spiu; | ||
SPIREG(SPI0U1)= spiu1; | ||
SPIREG(SPI0U2)= spiu2; | ||
|
||
if (writeWords>0) { | ||
// copy the outgoing data to the SPI hardware | ||
uint32_t *src=data; | ||
volatile uint32_t *dst=&SPIREG(SPI0W0); | ||
for (uint32_t i=0; i<writeWords; i++) | ||
*dst++ = *src++; | ||
} | ||
|
||
// Start the transfer | ||
SPIREG(SPI0CMD) = spicmdusr; | ||
|
||
// wait for the command to complete (typically only 1-3 iterations) | ||
uint32_t timeout = 1000; | ||
while ((SPIREG(SPI0CMD) & spicmdusr) && timeout--); | ||
|
||
if ((readWords>0) && (timeout>0)) { | ||
// copy the response back to the buffer | ||
uint32_t *dst=data; | ||
volatile uint32_t *src=&SPIREG(SPI0W0); | ||
for (uint32_t i=0; i<readWords; i++) | ||
*dst++ = *src++; | ||
} | ||
|
||
// Restore saved registers | ||
SPIREG(SPI0U) = oldSPI0U; | ||
SPIREG(SPI0U2)= oldSPI0U2; | ||
SPIREG(SPI0C) = oldSPI0C; | ||
|
||
PRECACHE_END(); | ||
return (timeout>0 ? SPI_RESULT_OK : SPI_RESULT_TIMEOUT); | ||
} | ||
|
||
|
||
/* SPI0Command: send a custom SPI command. | ||
* This part calculates register values and passes them to _SPI0Command(). | ||
* Parameters: | ||
* cmd The command byte (first 8 bits) to send to the SPI device | ||
* *data The buffer containing the outgoing data for the SPI bus. | ||
* The data is expected to be mosi_bits long, and the buffer | ||
* is overwritten by the incoming bus data, which will be | ||
* miso_bits long. | ||
* mosi_bits | ||
* Number of bits to be sent after the command byte. | ||
* miso_bits | ||
* Number of bits to read from the SPI bus after the outgoing | ||
* data has been sent. | ||
* | ||
* Note: This code has only been tested with SPI bus 0, but should work | ||
* equally well with other busses. The ESP8266 has bus 0 and 1, | ||
* newer chips may have more one day. | ||
*/ | ||
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits) { | ||
devyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (mosi_bits>(64*8)) | ||
return SPI_RESULT_ERR; | ||
if (miso_bits>(64*8)) | ||
return SPI_RESULT_ERR; | ||
|
||
// Calculate the number of data words (aka registers) that need to be copied | ||
// to/from the SPI controller. | ||
uint32_t mosi_words=mosi_bits/32; | ||
uint32_t miso_words=miso_bits/32; | ||
if (mosi_bits % 32 != 0) | ||
mosi_words++; | ||
if (miso_bits % 32 != 0) | ||
miso_words++; | ||
|
||
// Select user defined command mode in the controller | ||
uint32_t spiu=SPIUCOMMAND; //SPI_USR_COMMAND | ||
devyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Set the command byte to send | ||
uint32_t spiu2 = ((7 & SPIMCOMMAND)<<SPILCOMMAND) | cmd; | ||
|
||
uint32_t spiu1 = 0; | ||
if (mosi_bits>0) { | ||
// set the number of outgoing data bits to send | ||
spiu1 |= ((mosi_bits-1) & SPIMMOSI) << SPILMOSI; | ||
spiu |= SPIUMOSI; // SPI_USR_MOSI | ||
} | ||
if (miso_bits>0) { | ||
// set the number of incoming bits to read | ||
spiu1 |= ((miso_bits-1) & SPIMMISO) << SPILMISO; | ||
spiu |= SPIUMISO; // SPI_USR_MISO | ||
} | ||
|
||
uint32_t spic = SPI0C; | ||
// Select the most basic IO mode for maximum compatibility | ||
// Some flash commands are only available in this mode. | ||
spic &= ~(SPICQIO | SPICDIO | SPICQOUT | SPICDOUT | SPICAHB | SPICFASTRD); | ||
spic |= (SPICRESANDRES | SPICSHARE | SPICWPR | SPIC2BSE); | ||
|
||
SpiOpResult rc =_SPICommand(0,spic,spiu,spiu1,spiu2,data,mosi_words,miso_words); | ||
|
||
if (rc==SPI_RESULT_OK) { | ||
// clear any bits we did not read in the last word. | ||
if (miso_bits % 32) { | ||
data[miso_bits/32] &= ~(0xFFFFFFFF << (miso_bits % 32)); | ||
} | ||
} | ||
return rc; | ||
} | ||
|
||
} // namespace experimental |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
spi_utils.h - SPI utility function | ||
Copyright (c) 2015 Ivan Grokhotkov. All right reserved. | ||
|
||
This library is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
License as published by the Free Software Foundation; either | ||
version 2.1 of the License, or (at your option) any later version. | ||
|
||
This library is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
Lesser General Public License for more details. | ||
|
||
You should have received a copy of the GNU Lesser General Public | ||
License along with this library; if not, write to the Free Software | ||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
*/ | ||
|
||
|
||
#ifndef SPI_UTILS_H | ||
#define SPI_UTILS_H | ||
|
||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include <stdint.h> | ||
|
||
namespace experimental { | ||
typedef enum { | ||
ChocolateFrogsNuts marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SPI_RESULT_OK, | ||
SPI_RESULT_ERR, | ||
SPI_RESULT_TIMEOUT | ||
} SpiOpResult; | ||
|
||
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits); | ||
} | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
|
||
#endif //SPI_UTILS_H |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.