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.