Electronic – shift by 1 bit error in SPI

serialspitm4c123g

I am trying to implement the SPI communication on TM4C123.
I have 1 board and try to send data from SSI1(master) to SSI0(slave), but I observe that the received value is always shifted to the left by 1 bit!!
for example, I send 0x01 on the master and receive 0x02 on the slave, and so on.
the SPI settings I used are:

  • clocking of 8 MHz
  • CPOL and CPH are zeros on both SPI modules
  • 8 bit for the data field

Can anyone suggest a solution ??

EDIT: Here is the code

void SSI0_Init(void) ;

void SSI1_Init(void) ;

int main(){
    SSI1_Init();
    SSI0_Init();
    InitConsole() ;

    while(1){
    // set ss low
    GPIO_PORTD_DATA_R &= ~0x40 ;            // ss low
    while ((SSI1_SR_R & 0x02) == 0 ){}      //wait till fifo not full
    SSI1_DR_R = 0x01 ;                      // send char a
    while (SSI1_SR_R & 0x10){}              // wait for TX complete
    GPIO_PORTD_DATA_R |= 0x40 ;             // ss high

    uint8_t data ;
    while ((SSI0_SR_R & 0x04) == 0){}       // wait for not empty fifo flag
    data = SSI0_DR_R ;                      // data reading


    // set ss low
    GPIO_PORTD_DATA_R &= ~0x40 ;            // ss low
    while ((SSI1_SR_R & 0x02) == 0 ){}      //wait till fifo not full
    SSI1_DR_R = 0x02 ;                      // send char a
    while (SSI1_SR_R & 0x10){}              // wait for TX complete
    GPIO_PORTD_DATA_R |= 0x40 ;             // ss high

    while ((SSI0_SR_R & 0x04) == 0){}       // wait for not empty fifo flag
    data = SSI0_DR_R ;                      // data reading


    // set ss low
    GPIO_PORTD_DATA_R &= ~0x40 ;            // ss low
    while ((SSI1_SR_R & 0x02) == 0 ){}      //wait till fifo not full
    SSI1_DR_R = 0x04 ;                      // send char a
    while (SSI1_SR_R & 0x10){}              // wait for TX complete
    GPIO_PORTD_DATA_R |= 0x40 ;             // ss high

    while ((SSI0_SR_R & 0x04) == 0){}       // wait for not empty fifo flag
    data = SSI0_DR_R ;                      // data reading

    int dummy = data ;

    }
}

void SSI0_Init(void){

    // settings for TX, RX, SS, CLK in GPIO PORTA
    SYSCTL_RCGCGPIO_R |= 0x01 ;     // clock on PORTA
    SYSCTL_RCGCSSI_R |= 0x01 ;      // clock on SSI0 module
    GPIO_PORTA_AFSEL_R |= 0x1c ;    // alt. function for PORTA 2, 3, 4, 5
    GPIO_PORTA_PCTL_R &= ~0x000fff00 ;
    GPIO_PORTA_PCTL_R |= 0x00022200;
    GPIO_PORTA_DEN_R |= 0x1c ;      // digital enable

    // settings of SSI0 module
    SSI0_CR1_R = 0 ;                // disable during configuration
    SSI0_CC_R = 0 ;                 // system clock
    //SSI0_CPSR_R = 2 ;               // prescaler div by 2
    SSI0_CR0_R = 0x07 ;             // 8MHZ, SPI mode, 8 bit frame, 2nd edge capture
    SSI0_CR1_R |= 0x04 ;            // set as a slave
    SSI0_CR1_R |= 0x02 ;            // enable
}

void SSI1_Init(void){

    // settings for TX, RX, SS, CLK in GPIO PORTA

    SYSCTL_RCGCGPIO_R |= 0x08 ;     // clock on PORTD
    SYSCTL_RCGCSSI_R |= 0x02 ;      // clock on SSI1 module
    GPIO_PORTD_AFSEL_R |= 0x09 ;    // alt. function for PORTD 0,3
    GPIO_PORTD_PCTL_R &= ~0x0f00f ;
    GPIO_PORTD_PCTL_R |= 0x02002;
    GPIO_PORTD_DEN_R |= 0x09 ;      // digital enable

    // settings for PD6 as SS signal
    GPIO_PORTD_DIR_R |= 0x40 ;      // PD6 output
    GPIO_PORTD_DEN_R |= 0x40 ;      // digital enable PD6
    GPIO_PORTD_DATA_R |= 0x40 ;     // keep SS idle high

    // settings of SSI1 module
    SSI1_CR1_R = 0 ;                // disable during configuration
    SSI1_CC_R = 0 ;                 // system clock
    SSI1_CPSR_R = 2 ;               // prescaler div by 2
    SSI1_CR0_R |= 0x07 ;            // 8MHZ, SPI mode, 8 bit frame
    SSI1_CR1_R = 0x00 ;             // set as a master
    SSI1_CR1_R |= 0x02 ;            // enable
}

Best Answer

"Shifted by one bit" is the common symptom of SPI when the wrong clock setup is used. Either the master and slave disagree on what clock edge data is transferred, or you are starting at the wrong polarity from idle.

The first and obvious thing to do is to transfer a known test byte and look at the resulting chip select, clock, and data lines with a scope. Now compare that to what the slave device says it needs, and you will probably find a discrepancy.

Unfortunately, all four possible combinations of SPI clock idle polarity and active edge polarity are out there. You have to carefully read what your slave needs, then carefully read the datasheet of the master to see how to achieve that.