Skip to content

SPI.transfer(buffer, size) definition incompatible with other cores #5787

Closed
@s-light

Description

@s-light

challenge

i try to use the ulrichstern/Tlc59711 LED-Driver library to use with an ESP32 Dev Module.

this currently results in this compilation error:

/home/stefan/mydata/arduino_sketchbook/libraries/ulrichstern_Tlc59711/Tlc59711.cpp: In member function 'void Tlc59711::xferSpi()':
/home/stefan/mydata/arduino_sketchbook/libraries/ulrichstern_Tlc59711/Tlc59711.cpp:148:39: error: no matching function for call to 'SPIClass::transfer(uint16_t*&, int)'
       SPI.transfer(buffer2, bufferSz*2);
                                       ^
In file included from /home/stefan/mydata/arduino_sketchbook/libraries/ulrichstern_Tlc59711/Tlc59711.cpp:11:
/home/stefan/.arduino15/packages/esp32/hardware/esp32/2.0.0/libraries/SPI/src/SPI.h:70:10: note: candidate: 'void SPIClass::transfer(uint8_t*, uint32_t)'
     void transfer(uint8_t * data, uint32_t size);
          ^~~~~~~~
/home/stefan/.arduino15/packages/esp32/hardware/esp32/2.0.0/libraries/SPI/src/SPI.h:70:10: note:   no known conversion for argument 1 from 'uint16_t*' {aka 'short unsigned int*'} to 'uint8_t*' {aka 'unsigned char*'}
/home/stefan/.arduino15/packages/esp32/hardware/esp32/2.0.0/libraries/SPI/src/SPI.h:71:13: note: candidate: 'uint8_t SPIClass::transfer(uint8_t)'
     uint8_t transfer(uint8_t data);
             ^~~~~~~~
/home/stefan/.arduino15/packages/esp32/hardware/esp32/2.0.0/libraries/SPI/src/SPI.h:71:13: note:   candidate expects 1 argument, 2 provided

after some research i found that in the ESP32 core the definition of SPI.transfer(buffer, size) differs to other cores.

Minimal Example

with this the error can be reproduces if the board is a ESP32 Dev Kit
with AVR or SAMD it is compiling fine.

#include <SPI.h>

void setup() {
    SPI.begin();
    SPI.beginTransaction(SPISettings(2*1000*1000, MSBFIRST, SPI_MODE0));

    uint16_t *buffer;
    const uint16_t bufferSz = 10;
    buffer = reinterpret_cast<uint16_t*>(malloc(2*bufferSz));

    SPI.transfer(buffer, bufferSz*2);
}

void loop() {
}

down the rabbit hole

currently the definition is:
libraries/SPI/src/SPI.h#70

void transfer(uint8_t * data, uint32_t size);

libraries/SPI/src/SPI.cpp#229

void SPIClass::transfer(uint8_t * data, uint32_t size) 
{ 
	transferBytes(data, data, size); 
}

this was added in #2136.

in the avr core its defined as

inline static void transfer(void *buf, size_t count) {

and in the samd core as

void transfer(void *buf, size_t count);

solution

so to be cross-platform compatible it is needed to change the parameters to the same types - void *data, size_t count

i don't know yet what is need to get the called transferBytes function to work with this.
i tested with this implementation:

void SPIClass::transfer(void * data, size_t size)
{
    transferBytes(
        reinterpret_cast<uint8_t*>(data),
        reinterpret_cast<uint8_t*>(data),
        size);
}

its inspired by the other implementations - and it seems to work.
but i am not 100% sure if there are other side effects - so please review!

Hardware

Board: ESP32 Dev Module
Core Installation version: 2.0.0
IDE name: Arduino IDE
Flash Frequency: 80Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Kubuntu 20.04

Activity

me-no-dev

me-no-dev commented on Oct 21, 2021

@me-no-dev
Member

how about you uint8_t *buffer; buffer = reinterpret_cast<uint8_t*>(malloc(2*bufferSz)); instead?

s-light

s-light commented on Oct 21, 2021

@s-light
Author

i can change the library - the buffer is used as uint16_t type - so this does not make much sens to change.
i can also do

SPI.transfer(reinterpret_cast<uint8_t*>buffer, bufferSz*2);

in the library.

my main request was to fine tune for an cross-core-compatible API

Rotzbua

Rotzbua commented on Oct 23, 2021

@Rotzbua
Contributor

@s-light Do not use the core implementations as reference because they may have different implementations. Better use the official ArduinoCore-API repository https://github.com/arduino/ArduinoCore-API .

The reference API has the virtual void transfer(void *buf, size_t count) signature. https://github.com/arduino/ArduinoCore-API/blob/e03b65374c614130aa1b11597e07b3b5089a726d/api/HardwareSPI.h#L109-L111

So I agree that there should be a change or pass through to have better interoperability.

s-light

s-light commented on Nov 1, 2021

@s-light
Author

@Rotzbua thanks for the pointer to the core api.
i did not know that this exists...

so the best way would be

void SPIClass::transfer(void *buf, size_t count)
{
    transferBytes(
        reinterpret_cast<uint8_t*>(buf),
        reinterpret_cast<uint8_t*>(buf),
        count);
}

should i create a pullrequest with this change?

FrankBoesing

FrankBoesing commented on Nov 3, 2021

@FrankBoesing
Contributor

I agree, this is just incompatible to arduino, which uses void*

VojtechBartoska

VojtechBartoska commented on Apr 7, 2022

@VojtechBartoska
Contributor

Hello @s-light, is this issue still valid?

s-light

s-light commented on Apr 7, 2022

@s-light
Author

i will look at it and recheck...
please give me some days.

Rotzbua

Rotzbua commented on Apr 7, 2022

@Rotzbua
Contributor

@s-light @VojtechBartoska I checked. The issue is still valid.
Still: void transfer(uint8_t * , uint32_t )
Should: void transfer(void *, size_t )

10 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions

    `SPI.transfer(buffer, size)` definition incompatible with other cores · Issue #5787 · espressif/arduino-esp32