Go Down

Topic: SPI Slave [SOLVED] (Read 5633 times) previous topic - next topic

zuzzuz

Aug 15, 2012, 10:52 pm Last Edit: Sep 07, 2012, 07:34 am by zuzzuz Reason: 1
Hi, i need to use my arduino as slave spi, master is a st discovery board.
I use this sketch to configure spi:
Code: [Select]
#include <SPI.h>


#define SCK_PIN   13
#define MISO_PIN  12
#define MOSI_PIN  11
#define SS_PIN    10

void SlaveInit(void) {
 // Set MISO output, all others input
 pinMode(SCK_PIN, INPUT);
 pinMode(MOSI_PIN, INPUT);
 pinMode(MISO_PIN, OUTPUT);
 pinMode(SS_PIN, INPUT);

 // Enable SPI
 SPCR = B00000000;
 SPCR = (1<<SPE);
}

uint8_t ReadByte(void) {
 while(!(SPSR & (1<<SPIF))) ;
 return SPDR;
}

void WriteByte(uint8_t value) {
 SPDR = value;
 while (!(SPSR & (1<<SPIF))) ;
 return;
}




void setup()
{
 Serial.begin(9600);
 SlaveInit();
}

void loop()
{
uint8_t RX_Data;
 RX_Data = ReadByte();
 WriteByte(0x01);
 Serial.println(RX_Data);
//  Serial.println(RX_Data, HEX);
 Serial.println("rx");
}


This is the configuration of master
Code: [Select]
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
 SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
 SPI_InitStructure.SPI_CRCPolynomial = 7;
 SPI_Init(SPIy, &SPI_InitStructure);


I send this
Code: [Select]
uint8_t SPIy_Buffer_Tx[BufferSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
                                     0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
                                     0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
                                     0x1D, 0x1E, 0x1F, 0x20};

but i recive this
Code: [Select]


FFFFFFC0
rx
40
rx
FFFFFF88
rx
18
rx
FFFFFFF0
rx
FFFFFFF0
rx
30
rx
10
rx
20
rx
4
rx
FFFFFF88
rx
50
rx
60
rx
40
rx
78
rx
58
rx
68
rx
48
rx
70
rx
50
rx
60
rx
40
rx
FFFFFFF8
rx
4
rx

someone can help me to understand where i do something wrong?
thx.

pylon

If I interpret this configuration of the master correctly you chose the wrong mode on the slave side:

Code: [Select]
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;


Does this mean SCK is active LOW and the second edge is the time the data is viable? If so I think the mode on the slave side should be 3 and not 0 according to this picture http://en.wikipedia.org/wiki/File:SPI_timing_diagram2.svg

If the modes are not equal a correct transmission is not possible.

Graynomad

How fast is the master sending data?

I suspect while you are faffing around with Serial.print()s you receive about 20 bytes in the SPI.

I would accumulate ALL the data then print it.

Also because the two events (SPI and serial) are asynchronous you probably read SPDR half way through receiving a byte.

I think there are issues with the way you are returning data as well, but let's get one direction working first.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

zuzzuz

#3
Aug 16, 2012, 05:21 pm Last Edit: Aug 16, 2012, 05:29 pm by zuzzuz Reason: 1

If I interpret this configuration of the master correctly you chose the wrong mode on the slave side:

Code: [Select]
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;


Does this mean SCK is active LOW and the second edge is the time the data is viable? If so I think the mode on the slave side should be 3 and not 0 according to this picture http://en.wikipedia.org/wiki/File:SPI_timing_diagram2.svg

If the modes are not equal a correct transmission is not possible.


Thx, i try to change it in this way
Code: [Select]
SPIE - Enables the SPI interrupt when 1
SPE - Enables the SPI when 1
DORD - Sends data least Significant Bit First when 1, most Significant Bit first when 0
MSTR - Sets the Arduino in master mode when 1, slave mode when 0
CPOL - Sets the data clock to be idle when high if set to 1, idle when low if set to 0
CPHA - Samples data on the falling edge of the data clock when 1, rising edge when 0
SPR1 and SPR0 - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)

with the master configuration i think i need:
DORD = 1
CPOL = 1
CPHA = 1
Is it now correct?



How fast is the master sending data?

I suspect while you are faffing around with Serial.print()s you receive about 20 bytes in the SPI.

I would accumulate ALL the data then print it.

Also because the two events (SPI and serial) are asynchronous you probably read SPDR half way through receiving a byte.

I think there are issues with the way you are returning data as well, but let's get one direction working first.

______
Rob


I don't know the spi clock of stm32vldiscovery, i know internal max clock is 24mhz.
With 2 stm32 code of master work perfectly then problem isn't in master code,
I try to use a new variable to store spi data received and then i print it as u say.
Thx for help.

pylon

Quote
with the master configuration i think i need:
DORD = 1
CPOL = 1
CPHA = 1
Is it now correct?


I don't know if it's correct as I have no clue about your master's configuration but if my interpretation of the parameters is correct, then I would use these values.

zuzzuz

nothing :(
I changed  configuration, but receive and send data are different.
I also try to change master-slave, with arduino configuration master and stm32 slave, for being sure that isn't a clock rate problem, but in this situation no data arrive to slave.
Someone can give me a little help?

Graynomad

Post your current code.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

zuzzuz

This is new code
Code: [Select]
#include <SPI.h>


#define SCK_PIN   13
#define MISO_PIN  12
#define MOSI_PIN  11
#define SS_PIN    10

void SlaveInit(void) {
  // Set MISO output, all others input
  pinMode(SCK_PIN, INPUT);
  pinMode(MOSI_PIN, INPUT);
  pinMode(MISO_PIN, OUTPUT);
  pinMode(SS_PIN, INPUT);

  // Enable SPI
  SPCR = B00101100;
  SPCR = (1<<SPE);
}

uint8_t ReadByte(void) {
  while(!(SPSR & (1<<SPIF))) ;
  return SPDR;
}

void WriteByte(uint8_t value) {
  SPDR = value;
  while (!(SPSR & (1<<SPIF))) ;
  return;
}




void setup()
{
  Serial.begin(9600);
  SlaveInit();
}

void loop()
{
uint8_t RX_Data[32];
for (int i = 1;i<=32;i++){
  RX_Data[i] = ReadByte();
  WriteByte(0x01);
}
 
 
for (int i = 1;i<=32;i++){
  Serial.println(RX_Data[i]);
//  Serial.println(RX_Data, HEX);
  Serial.println("rx");
}
}

Graynomad

You are putting data into RX_Data starting at index 1 (normally you start at 0) then you count to 32, so you overrun the end of the array.

But I suspect that this code

Code: [Select]
  RX_Data[i] = ReadByte();
  WriteByte(0x01);


Takes way to long, you haven't said how fast the SPI link is running but remember that when a byte is received you have one bit time to read it before it starts getting overwritten with the next byte.

With any decent SPI link that's just a few uS, not enough time for function calls and indexing into arrays.

I would propose something like this

Code: [Select]
uint8_t RX_Data[32];

uint8_t ReadPacket(void) {
ptr = RX_Data;
for (int i = 0; i < 32; i++){
SPDR = 0x01; // preload the data reg
while(!(SPSR & (1<<SPIF))) ; // wait for new byte
*ptr++ = SPDR; // save byte
}
}

void loop() {
   ReadPacket ();
   ...
   }
 


______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

zuzzuz

thx for help this is my new code (following what u have said)
Code: [Select]
#include <SPI.h>


#define SCK_PIN   13
#define MISO_PIN  12
#define MOSI_PIN  11
#define SS_PIN    10

void SlaveInit(void) {
  // Set MISO output, all others input
  pinMode(SCK_PIN, INPUT);
  pinMode(MOSI_PIN, INPUT);
  pinMode(MISO_PIN, OUTPUT);
  pinMode(SS_PIN, INPUT);

  // Enable SPI
  SPCR = B00101100;
  SPCR = (1<<SPE);
}
uint8_t RX_Data[32];

uint8_t ReadByte(void) {
uint8_t *ptr = RX_Data;
for (int i = 0; i < 32; i++){
SPDR = 0x01; // preload the data reg
  while(!(SPSR & (1<<SPIF))) ;
*ptr++ = SPDR; // save byte
}
}

void WriteByte(uint8_t value) {
  SPDR = value;
  while (!(SPSR & (1<<SPIF))) ;
  return;
}




void setup()
{
  Serial.begin(9600);
  SlaveInit();
}

void loop()
{


ReadByte();
 
 
for (int i = 1;i<=32;i++){
  Serial.println(RX_Data[i]);
//  Serial.println(RX_Data, HEX);
  Serial.println("rx");
}
}


and this is the result from board

Code: [Select]

1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
1
rx
0
rx

i send
Code: [Select]
uint8_t SPIy_Buffer_Tx[BufferSize] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                      0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
                                      0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
                                      0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
                                      0x1D, 0x1E, 0x1F, 0x20};

a little more help?
P.S.
I configured stm32 to 2MHZ spi speed

Graynomad

I would remove this

SPDR = 0x01;          // preload the data reg

It's not really helping as you don't have to reply to the master it seems.

Also modify the for() loop to count from 0 to 31, that's not the problem but as I said before you are counting off the end of the array. Check the loop in ReadByte().

But I really can't see what's wrong and without a logic analyser it's very difficult to see because you can't do serial.print debugging in such a real time function.

But then I look at this

Code: [Select]
for (int i = 1;i<=32;i++){
  Serial.println(RX_Data[i]);
//  Serial.println(RX_Data, HEX);
  Serial.println("rx");
}


All the bytes in the array are non-printable ASCII characters so they won't show. Why you get all 1s I'm not sure but anyway we need to see exactly what is in that array. Try this

Code: [Select]
for (int i = 0;i<32;i++){  // note loop values
  Serial.print(RX_Data[i], HEX);
  Serial.println(',');
}


______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

zuzzuz

#11
Aug 24, 2012, 02:36 pm Last Edit: Aug 24, 2012, 02:54 pm by zuzzuz Reason: 1
Situation:
Code: [Select]
#include <SPI.h>

#define SCK_PIN   13
#define MISO_PIN  12
#define MOSI_PIN  11
#define SS_PIN    10

void SlaveInit(void) {
 // Set MISO output, all others input
 pinMode(SCK_PIN, INPUT);
 pinMode(MOSI_PIN, INPUT);
 pinMode(MISO_PIN, OUTPUT);
 pinMode(SS_PIN, INPUT);

 // Enable SPI
 SPCR = B00101100;
 SPCR = (1<<SPE);
}
uint8_t RX_Data[32];

uint8_t ReadByte(void) {
uint8_t *ptr = RX_Data;
for (int i = 0; i < 32; i++){
// SPDR = 0x01; // preload the data reg
 while(!(SPSR & (1<<SPIF))) ;
*ptr++ = SPDR; // save byte
}
}

void setup()
{
 Serial.begin(9600);
 SlaveInit();
}

void loop()
{

ReadByte();

for (int i = 0;i<32;i++){  // note loop values
 Serial.print(RX_Data[i], HEX);
 Serial.println(',');
}
}


Result:
Code: [Select]
0,
40,
40,
20,
20,
60,
60,
10,
10,
50,
50,
30,
30,
70,
70,
8,
8,
48,
48,
28,
28,
68,
68,
18,
18,
58,
58,
38,
38,
78,
78,
4,


Update:
Code: [Select]
60,
10,
10,
50,
50,
30,
30,
70,
70,
8,
8,
48,
48,
28,
28,
68,
68,
18,
18,
58,
58,
38,
38,
78,
78,
4,
0,
40,
40,
20,
20,
60,
4,
0,
40,
40,
20,
20,
60,
60,
10,
10,
50,
50,
30,
30,
70,
70,
8,
8,
48,
48,
28,
28,
68,
68,
18,
18,
58,
58,
38,
38,
78,
78,

If i run sketch in another istance i have this.... why if i have a for loop 32 times i receive more than 32 value  :smiley-eek: i'm going crazy

zuzzuz

#12
Aug 26, 2012, 04:04 pm Last Edit: Aug 26, 2012, 04:16 pm by zuzzuz Reason: 1
i post my hardware configuration for master.... i hope this is useful
Code: [Select]
void GPIO_Configuration()
{
// SPIy_Mode == SPI_Mode_Master
 GPIO_InitTypeDef GPIO_InitStructure;


 /* Configure NSS pin as Output Push Pull */
 GPIO_InitStructure.GPIO_Pin = SPIy_PIN_NSS;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(SPIy_GPIO, &GPIO_InitStructure);
     
 /* Configure SPIy pins: SCK, MISO and MOSI ---------------------------------*/
 /* Configure SCK and MOSI pins as Alternate Function Push Pull */
 GPIO_InitStructure.GPIO_Pin = SPIy_PIN_SCK | SPIy_PIN_MOSI;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(SPIy_GPIO, &GPIO_InitStructure);
 
 /* Configure MISO pin as Input Floating  */
 GPIO_InitStructure.GPIO_Pin = SPIy_PIN_MISO;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
 GPIO_Init(SPIy_GPIO, &GPIO_InitStructure);
   
}


And
Code: [Select]
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  // SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPIy, &SPI_InitStructure);

Graynomad

Quote
why if i have a for loop 32 times i receive more than 32 value

By my count you have 64 values which is 2x32, that's probably not a coincidence. There's obviously a pattern there but I can't see how it relates to the transmitted data.

How often is the master sending? Can you change it to only transmit once?
How are you getting in sync with the master? If the slave starts reading at any old time you will get crap data.
Can you fill the RX_Data array with a known value (say 0xAA) in setup() so we know those values are actually coming from the SPI.

Can you change the print to this

Code: [Select]
for (int i = 0;i<32;i++){  // note loop values
  Serial.print(RX_Data[i], HEX);
  Serial.print(',');
}
    Serial.println('');


So we don't have to scroll so much and it will make it obvious how many times we get data.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

zuzzuz


Quote

How often is the master sending? Can you change it to only transmit once?
How are you getting in sync with the master? If the slave starts reading at any old time you will get crap data.
Can you fill the RX_Data array with a known value (say 0xAA) in setup() so we know those values are actually coming from the SPI.

Can you change the print to this

Code: [Select]
for (int i = 0;i<32;i++){  // note loop values
  Serial.print(RX_Data[i], HEX);
  Serial.print(',');
}
    Serial.println('');


So we don't have to scroll so much and it will make it obvious how many times we get data.

______
Rob

i use this code to master
Code: [Select]
while (1)
  {
   
    while(!STM32vldiscovery_PBGetState(BUTTON_USER));
   
   
    /* Transfer procedure */
    for(TxIdx=0;TxIdx < BufferSize;TxIdx++)
    {
      GPIO_ResetBits(SPIy_GPIO, SPIy_PIN_NSS );
     
      //    /* Wait for SPIy Tx buffer empty */
      while (SPI_I2S_GetFlagStatus(SPIy, SPI_I2S_FLAG_TXE) == RESET);
     
      //    /* Send SPIy data */
      SPI_I2S_SendData(SPIy, SPIy_Buffer_Tx[TxIdx]);
     
      //    /* Wait for SPIy data reception */
      while (SPI_I2S_GetFlagStatus(SPIy, SPI_I2S_FLAG_RXNE) == RESET);
//      ////    /* Read SPIz received data */
      rec=SPI_I2S_ReceiveData(SPIy);
      //   
      GPIO_SetBits(SPIy_GPIO, SPIy_PIN_NSS );
     
    }

i start sending data when i push button, i think only 32 data has sent.
Master speed as i write in configuration is 2MHZ

Go Up