I need to have Arduino Giga working as SPI slave device. Using the following code I'm able to receive data from master:
void setup()
{
mbed::SPISlave spi(SPI_MOSI1, SPI_MISO1, SPI_SCK1, SPI_SS1);
spi.frequency(2000000);
spi.format(8, 0);
spi.reply(0x00);
}
void update()
{
if(spi.receive())
{
const byte data = static_cast<byte>(spi.read());
....
spi.reply(0xAA); // test value
}
}
However this code block on reply() function after a few times the function is called. I'm also not able to receive the reply data when the call doesn't block. I always receive the first byte passed to reply after the initialization (that in this example is 0x00).
I really don't understand why I experiment this block since the code is really simple.
Someone experienced a similar issue and know how to get it working?
Thank you
I don't know but I also tried I2CSlave and work as expected so I don't think the two issues can be related. However it's true I don't know the current mbed version I'm using since I develop using VSC with Platformio extension. I'll check...
@DrDiettrich and this should justify the block of reply() call? By the way I tried all the possible combinations of read/reply but without success. After 8 or 9 times the function reply() is called it does not return and block all. Checking the mbed source I can see the reply() call refer to the function:
Probably my knowledge about SPI is very poor but in my understanding when master move CS and start transaction by activating clock the buffers are switched and the in/out bytes are exchanged between master and slave. Always one in byte and one out byte so what is a buffer for?
So the return data should be set on SS start, before the next byte is received.
As code how should this be handled? SPISlave class export only receive(), read() and reply() methods. How to use these methods to manage the situation you described?
Thank you
Reported example in the documentation is the following:
int main()
{
device.reply(0x00); // Prime SPI with first reply
while (1) {
if (device.receive()) {
int v = device.read(); // Read byte from master
v = (v + 1) % 0x100; // Add one to it, modulo 256
device.reply(v); // Make this the next reply
}
}
}
In my case I check if data is received inside the Arduino loop() function instead of have an infinite while loop. Excluding this point the code is the same but doesn't work as explained. Can you show me how to modify this code based to your suggestion?
Thank you
What is the diffrence of your change compared with my initial (blocking) example? It's basically the same I do in my test and, as reported, after around 8/9 calls the reply() function stop to return...
You are right, my code is not okay. Use these funtions instead:
bool replyWaiting;
byte replyData; //next reply to transmit
void checkReply() { //to be called in loop()
if (digitalread(SPI_SS1) == 0 && replyWaiting)
SPI.reply(replyData);
replyWaiting = false;
}
}
//call whenever you have new data to reply
void setReply(byte repData) {
replyData = repData;
replyWaiting = true;
}
At first I really thank you for your time. Unfortunately your solution doesn't work, same problem. The method reply() stop return after 8 calls blocking all. In add of this the replied bytes are not transmitted to the master. Opposite communication (from master to slave) work well. I start suspecting some bug in STD mbed management but since my lack in SPI knowledge I have some difficult to know where the problem is...
I think that it's time to define a specific protocol for your slave: This protocol is specific to every single slave device, that's why slave examples are given for specific slave devices only.
Your slave waits for an ongoing transmission (SS LOW), reads a byte from the master and generates a reply for the next transmission. After that second transmission the slave should be deselected.
The master selects a slave, sends a byte, then accepts a reply and deselects the slave. That's 2 transmissions. The slave should be selected during that transaction, deselected afterwards.