Skip to content

Allow unaligned input/output to SPI::transferBytes #5709

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 5 commits into from
Feb 3, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 57 additions & 16 deletions libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,6 @@ void SPIClass::writePattern(const uint8_t * data, uint8_t size, uint32_t repeat)
}

/**
* Note:
* in and out need to be aligned to 32Bit
* or you get an Fatal exception (9)
* @param out uint8_t *
* @param in uint8_t *
* @param size uint32_t
Expand All @@ -538,25 +535,29 @@ void SPIClass::transferBytes(const uint8_t * out, uint8_t * in, uint32_t size) {
* @param in uint8_t *
* @param size uint8_t (max 64)
*/
void SPIClass::transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size) {

void SPIClass::transferBytesAligned_(const uint8_t * out, uint8_t * in, uint8_t size) {
if (!size)
return;

while(SPI1CMD & SPIBUSY) {}
// Set in/out Bits to transfer

setDataBits(size * 8);

volatile uint32_t * fifoPtr = &SPI1W0;
volatile uint32_t *fifoPtr = &SPI1W0;
uint8_t dataSize = ((size + 3) / 4);

if(out) {
uint32_t * dataPtr = (uint32_t*) out;
while(dataSize--) {
if (out) {
uint32_t *dataPtr = (uint32_t*) out;
while (dataSize--) {
*fifoPtr = *dataPtr;
dataPtr++;
fifoPtr++;
}
} else {
// no out data only read fill with dummy data!
while(dataSize--) {
while (dataSize--) {
*fifoPtr = 0xFFFFFFFF;
fifoPtr++;
}
Expand All @@ -565,18 +566,58 @@ void SPIClass::transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size) {
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}

if(in) {
uint32_t * dataPtr = (uint32_t*) in;
if (in) {
uint32_t *dataPtr = (uint32_t*) in;
fifoPtr = &SPI1W0;
dataSize = ((size + 3) / 4);
while(dataSize--) {
*dataPtr = *fifoPtr;
dataPtr++;
fifoPtr++;
dataSize = size;
while (dataSize >= 4) {
*(dataPtr++) = *(fifoPtr++);
dataSize -= 4;
in += 4;
}
volatile uint8_t *fifoPtrB = (volatile uint8_t *)fifoPtr;
while (dataSize--) {
*(in++) = *(fifoPtrB++);
}
}
}


void SPIClass::transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size) {
if (!((uint32_t)out & 3) && !((uint32_t)in & 3)) {
// Input and output are both 32b aligned or NULL
transferBytesAligned_(out, in, size);
} else if (!out && ((uint32_t)in & 3)) {
// Input only and misaligned, do bytewise until in aligned
while (size && ((uint32_t)in & 3)) {
*(in++) = transfer(0xff);
size--;
}
transferBytesAligned_(out, in, size);
} else if (!in && ((uint32_t)out & 3)) {
// Output only and misaligned, bytewise xmit until aligned
while (size && ((uint32_t)out & 3)) {
transfer(*(out++));
size--;
}
transferBytesAligned_(out, in, size);
} else {
// HW FIFO has 64b limit, so just align in RAM and then send to FIFO aligned
uint8_t outAligned[64]; // Stack vars will be 32b aligned
uint8_t inAligned[64]; // Stack vars will be 32b aligned
if (out) {
memcpy(outAligned, out, size);
} else {
memset(outAligned, 0xff, size); // 0xff = no xmit data
}
transferBytesAligned_(outAligned, inAligned, size);
if (in) {
memcpy(in, inAligned, size);
}
}
}


#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPI)
SPIClass SPI;
#endif
1 change: 1 addition & 0 deletions libraries/SPI/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class SPIClass {
uint8_t pinSet;
void writeBytes_(const uint8_t * data, uint8_t size);
void transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size);
void transferBytesAligned_(const uint8_t * out, uint8_t * in, uint8_t size);
inline void setDataBits(uint16_t bits);
};

Expand Down