on serial terminal i always get "abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0abc0" whatever I sent. However, those lines are printed proves that interrupt is called. i therefore dont know where i was wrong on the processing of SPDR
You are not supposed to execute any methods on Serial object in an ISR. Before going to ISR, the MCU disables the global interrupt bit; whereas, Serial.print()/write() method is interrupt driven. The solution is:
Set a flag in the ISR() and then do your Serial.print()/write() job in the loop() function based on the flag value.
GolamMostafa:
You are not supposed to execute any methods on Serial object in an ISR. Before going to ISR, the MCU disables the global interrupt bit; whereas, Serial.print()/write() method is interrupt driven. The solution is:
Set a flag in the ISR() and then do your Serial.print()/write() job in the loop() function based on the flag value.
volatile bool flag1 = false;
ISR (SPI_STC_vect)
{
flag1 = true;
}
void loop (void)
{
if (flag1 == true)
{
byte c = SPDR;
char data[5];
sprintf (data, "abc%d", SPDR);
Serial.write(data, 4 );
if (c != NULL)
{
byte C = c - 32;
SPDR = C;
Serial.print("\nReceive:");
Serial.write(c);
Serial.print(",Respond:");
Serial.write(C);
flag1 = false;
}
}
delay(1000);
}
Thanks, did exactly what you posted but i still prints abc0abc0abc0abc0 while I sent byte 0x62
import spidev
import time
import binascii
spi = spidev.SpiDev() # create spi object
spi.open(0, 0)# open spi port 0, device (CS) 0
spi.max_speed_hz = 3900000
try:
while True:
print("send:b,",end="")
resp = spi.xfer2([0x62]) # transfer one byte
c = spi.readbytes(1)
for x in c:
print ("receieve:",chr(x))
time.sleep(1) # sleep for 0.1 seconds
except KeyboardInterrupt:
spi.close()
Slave is Ardunio Mega 1280. Its source was posted fully above. Slave echoes what it received from Master back. In this case, I sent 0x62
SPDR is not a register you can write and immediately read back and expect the same value. Writes go to the TX shift register, reads from the RX shift register.
Blackfin:
SPDR is not a register you can write and immediately read back and expect the same value. Writes go to the TX shift register, reads from the RX shift register.
Is there more setup() code that you didn't show? I'm not seeing as much SPI initialization as I expect, and the mixture of raw register manipulation with Arduino SPI.attachInterrupt() is worrisome.
There's this, from the Arduino code. Aside from the warning, and the fact that it's duplicating things that you've already done, it looks pretty safe.
// These undocumented functions should not be used. SPI.transfer()
// polls the hardware flag which is automatically cleared as the
// AVR responds to SPI's interrupt
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
Have you played with the clock polarity and phase settings?
spi.max_speed_hz = 3900000
Have you tried lower clock speeds? Theoretically an 16MHz AVR is supposed to receive SPI at up to 4MHz, but I'm not quite sure how clock synchronization works when it's almost at the limit.
westfw:
Is there more setup() code that you didn't show? I'm not seeing as much SPI initialization as I expect, and the mixture of raw register manipulation with Arduino SPI.attachInterrupt() is worrisome.
The OP is missing the following three codes in his initialization list:
pinMode(SS, INPUT_PULLUP); //to ensure SS/-pin remains at HIGH and in input mode
SPCR |= !(_BV(MSTR)); //Arduino is Slave
sei(); //Global interrupt bit is made active
This is a typical sketch for SPI-Slave that I use for functionality check of two SPI Arduinos using interrupt; where, I had to cancel the use of this code: SPI.attachInterrupt(). Slave-SPI Codes:
#include <SPI.h>
volatile bool flag1 = false, flag2 = false;
byte myData[] = {0xFA, 0x01, 0x0E};
int i = 0;
byte x;
void setup ()
{
Serial.begin(115200);
pinMode(SS, INPUT_PULLUP); // ensure SS stays high for now
pinMode(MISO, OUTPUT);
SPCR |= _BV(SPE);
SPCR |= !(_BV(MSTR)); //Arduino is Slave
SPCR |= _BV(SPIE); //SPI.attachInterrupt();
sei();
SPDR = 0x67; //test value
// delay(100);
}
void loop()
{
}
ISR(SPI_STC_vect)
{
if (flag1 == false)
{
x = SPDR;
if (x == 11)
{
flag1 = true;
}
}
SPDR = myData[i];
i++;
if (i == 3)
{
flag1 = false;
i = 0;
}
}
I don't think that line does what you're expecting it to do.
Fortunately, I think it ends up being a no-op, and the default state of the bit is what you wanted, anyway.
Should be a bitwise negation rather than a logical negation, and an &= to clear the bit...
westfw:
I don't think that line does what you're expecting it to do.
Fortunately, I think it ends up being a no-op, and the default state of the bit is what you wanted, anyway.
Should be a bitwise negation rather than a logical negation, and an &= to clear the bit...
SPCR &= ~(_BV(MSTR)); //Arduino is Slave
I did like this: SPCR |= !(_BV(MSTR)); from the following understanding:
Figure-1:
So the idea is to clear the MSTR bit, right?
An OR operation ("|=" included) never "clears" bits.
"!" is a logical NOT, not a bitwise NOT, so "!_BV(MSTR)" is "false" (0)
"x |= 0;" is a no-op.
_BV(MSTR) = 10
!_BV(MSTR) = 0
0s |= !_BV(MSTR) =0 bit clear, which is OK, but only because it was already clear.
1s |= !_BV(MSTR) =FF one bit wasn't cleared...
1. What does it do? Does it put HIGH at the MSTR bit of SPCR Register without affecting other bits? 2. What is the opcode(operation) here? 3. What is the operand here? Is it MSTR -- the single bit? 4. What does BV stand for (set Bit Value -- I had been telling like this to myself)? 5. Why has _BV started with underscore sign (_BV)?
GolamMostafa:
The OP is missing the following three codes in his initialization list:
pinMode(SS, INPUT_PULLUP); //to ensure SS/-pin remains at HIGH and in input mode
SPCR |= !(_BV(MSTR)); //Arduino is Slave
sei(); //Global interrupt bit is made active
This is a typical sketch for SPI-Slave that I use for functionality check of two SPI Arduinos using interrupt; where, I had to cancel the use of this code: SPI.attachInterrupt().
**Slave-SPI** Codes:
void setup ()
{
Serial.begin(115200);
pinMode(SS, INPUT_PULLUP); // ensure SS stays high for now
pinMode(MISO, OUTPUT);
SPCR |= _BV(SPE);
SPCR |= !(_BV(MSTR)); //Arduino is Slave
SPCR |= _BV(SPIE); //SPI.attachInterrupt();
sei();
SPDR = 0x67; //test value
// delay(100);
}
void loop()
{
}
ISR(SPI_STC_vect)
{
if (flag1 == false)
{
x = SPDR;
if (x == 11)
{
flag1 = true;
}
}
SPDR = myData[i];
i++;
if (i == 3)
{
flag1 = false;
i = 0;
}
}
i tried this with both SPCR &= ~(_BV(MSTR)); like you mentioned and CR &= ~(_BV(MSTR)); as @westfw. SPDR still is 0 whateever sent or assigned
i also tried clock is 500000 and 400000, still is the same result, SPDR could not be different from 0
in setup(), i added
sprintf (data,"abc%d",SPDR);
Serial.print(data );
to test if SPDR still is test value 0x67 and still get abc0 printed.
and it still prints abd0abd0. it seems that SPDR always is set as "0"
Well, writing to SPDR is a different operation from reading SPDR. Writing puts a byte in the output queue. Reading gets the last byte received.
Are you sure your MOSI line is connected to the Master? The interrupt happens after 8 clocks, even if the MOSI line is not connected.
Why are you including the SPI library and then using direct port manipulation?