CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

SPI Slave weird behaviour

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

SPI Slave weird behaviour
PostPosted: Mon Aug 19, 2013 1:48 am     Reply with quote

Goodday All

I am stump by the code below exiting a routine when it should not.
Hope somebody can spot my flaw.

PIC16F1518
CCS 5.010 and 4.141

http://imageshack.us/photo/my-images/826/e08w.jpg/
Code:

#include <16F1518.h>
#device ADC=10
#case
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES PUT                      //Power Up Timer
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES BORV25                   //Brownout reset at 2.5V
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(internal=16MHz)
#include <stdint.H>

#define RELAY1       PIN_A5
#define RELAY2       PIN_C5
#define SLAVE_SELECT PIN_B4
  #define SPI_CLK PIN_B7
  #define SPI_MOSI PIN_B5
  #define SPI_MISO PIN_B6

#ZERO_RAM

void ReceiveSPI(void) {
  uint8_t i;
 
  while (!input_state(SLAVE_SELECT)) {
   for (i=0; i<8; i++) {
     //Wait for SPI CLK to go low
     while (input_state(SPI_CLK)) {
       /*If SS high terminate and return*/
       if (input_state(SLAVE_SELECT)) {
         output_toggle(RELAY2);
         return;
       }
     }
     //Wait for SPI CLK to go high
     while (!input_state(SPI_CLK)) {
       //If SS high terminate and return
       if (input_state(SLAVE_SELECT)) {
         output_toggle(RELAY2);
         return;
       }
     }
   }
  }
}

void main() {
   set_tris_a(0x0C);
   set_tris_b(0xB9);
   set_tris_c(0x44);
   while(TRUE){
      //Monitor the SS line and enable SPI reception when low
      if (!input_state(SLAVE_SELECT)) { //Slave select is low
        ReceiveSPI();
        output_toggle(RELAY1);
      }
   }

}


What is happening is that the ReceiveSPI() should only exit when SLAVE_SELECT is high but as can be seen on the oscilloscope trace, that does not always work like that.

Ch 1 (yellow) is SCK from master
Ch 2 (blue) is CS from master
Ch 4 (green) is the output_toggle(RELAY1) which toggles every time I exit ReceiveSPI().

It can be seen that on the picture it exits while SLAVE_SELECT is still low, then re-enters and exit correctly when SLAVE_SELECT high.

Now the question is why does the code do this. PIC is running at 5V and input signals are at 5V as measured on the PIC pin in question. A LED is connected to 12V via a NPN transistor to ground, tha's why that is 12V.

Regards
Alan
Ttelmah



Joined: 11 Mar 2010
Posts: 19359

View user's profile Send private message

PostPosted: Mon Aug 19, 2013 2:07 am     Reply with quote

You are testing the same pins, at multiple places in the loop. Giving multiple exit routes.

The main loop in 'ReceiveSPI', will exit if SLAVE_SELECT is high at the moment it loops, doing nothing when it does. However It'll also exit if SLAVE_SELECT happens to go high in the moment after it tests the clock, this time toggling the relay. The behaviour is indeterminate, depending on when exactly relative to the loop, events happen.....

Best Wishes
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Aug 19, 2013 2:26 am     Reply with quote

Thanks Ttelmah.

The reason for multiple testing are if the SLAVE_SELECT goes high when waiting for a CLK change to exit the routine.

I want to refer to the attached oscilloscope trace again. It exits the loop after about 3.5ms with the SLAVE_SELECT pin still low. The pin goes high 2ms after this event.

Regards
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Aug 19, 2013 2:35 am     Reply with quote

Ttelmah

Changed the code to have only one exit out of the routine. Still the same behaviour. Does not happen every time, difficult to determine the timing but a guess would be once every 5 sec on average.

Code:

#include <16F1518.h>
#device ADC=10
#case
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES PUT                      //Power Up Timer
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES BORV25                   //Brownout reset at 2.5V
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(internal=16MHz)
#include <stdint.H>

#define RELAY1       PIN_A5
#define RELAY2       PIN_C5
#define SLAVE_SELECT PIN_B4
  #define SPI_CLK PIN_B7
  #define SPI_MOSI PIN_B5
  #define SPI_MISO PIN_B6

#ZERO_RAM

void ReceiveSPI(void) {
  uint8_t i;
 
  while (TRUE) { //!input_state(SLAVE_SELECT)) {
   for (i=0; i<8; i++) {
     //Wait for SPI CLK to go low
     while (input_state(SPI_CLK)) {
       /*If SS high terminate and return*/
       if (input_state(SLAVE_SELECT)) {
         output_toggle(RELAY2);
         return;
       }
     }
     //Wait for SPI CLK to go high
     while (!input_state(SPI_CLK));
   }
  }
}

void main() {
   set_tris_a(0x0C);
   set_tris_b(0xB9);
   set_tris_c(0x44);
   while(TRUE){
      //Monitor the SS line and enable SPI reception when low
      if (!input_state(SLAVE_SELECT)) { //Slave select is low
        ReceiveSPI();
        output_toggle(RELAY1);
      }
   }
}

Regards
Alan
Ttelmah



Joined: 11 Mar 2010
Posts: 19359

View user's profile Send private message

PostPosted: Mon Aug 19, 2013 3:21 am     Reply with quote

Point is that the trace, does not show it exiting with SS low. It looks as it it may be, but it you realise that your timing is 2mSec/division, I think the SS may actually be high at the time of exit.
You'd need to be running the scope with a much higher scan resolution to see what is happening.
Obvious possibilities are things like ringing on the SS line etc....
Also are you absolutely sure you have the connections the right way round?. Obvious 'pattern' to the exit's, is that the SCK is high at the time.

The new code looks much more likely to work right.

Best Wishes
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Mon Aug 19, 2013 7:51 am     Reply with quote

Well I managed to capture at 100us per div and SLAVE_SELECT still low.

[img]
http://imageshack.us/photo/my-images/89/mtny.jpg/
[/img]

Changed the code to detect the SLAVE_SELECT line high for 50 x 7 instructions and that seems to solve the problem, which seems to point to ringing that a 5GS/s scope could not detect.

Thanks Ttelmah appreciate your input.

Code:

void ReceiveSPI(void) {
  uint8_t i,SS_cnt;
 
  SS_cnt = 0;
  while (TRUE) { //!input_state(SLAVE_SELECT)) {
   for (i=0; i<8; i++) {
     //Wait for SPI CLK to go low
     while (input_state(SPI_CLK)) {
       /*If SS high terminate and return*/
       if (input_state(SLAVE_SELECT)) {
         //SS must be high for 50 counts
         if (SS_cnt++ > 50) return;
         
       }
       else SS_cnt = 0;
     }
     //Wait for SPI CLK to go high
     while (!input_state(SPI_CLK));
   }
  }
}


Regards
Alan
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group