[求助] 两块STM32F4之间spi握手通信问题

licdn   2013-4-16 23:21 楼主
我用两块STM32F4的SPI1双向通信,想实现主SPI发送1024个数据,从SPI收到的时候回复一个ack,主SPI收到这个ack的时候再发送1024个字节。有好几个问题想请教大侠。 首先主SPI的配置如下:
  1. GPIO_InitTypeDef GPIO_InitStruct;

    SPI_InitTypeDef SPI_InitStruct;

  2. // enable clock for used IO pins

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // connect SPI1 pins to SPI alternate function

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);

  3. // enable peripheral clock

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    /* configure SPI1 in Mode 0

    * CPOL = 0 --> clock is low when idle

    * CPHA = 0 --> data is sampled at the first edge

    */

    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines

    SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high

    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide

    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle

    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge

    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high

    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // SPI frequency is APB2 frequency / 4

    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first

    SPI_InitStruct.SPI_CRCPolynomial = 7;

    SPI1->CR1 |=0x1000;

    SPI1->CR2 |=0x20;

    SPI_Init(SPI1, &SPI_InitStruct);

  4. SPI_Cmd(SPI1, ENABLE); // enable SPI1

主机的发送接收函数:
  1. uint8_t SPI1_sendrecv(uint8_t data){

  2. SPI1->DR = data; // write data to be transmitted to the SPI data register

    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete

    while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete

    while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore

    return SPI1->DR; // return received data from SPI data register

    }

主机主函数发送:
  1. for(index_data=0;index_data

    receive_data[index_data]=SPI1_sendrecv(send_data[index_data]);

    }

    printf("%s\n\r",receive_data);

从机的配置:
  1. void init_SPI1(void){

    GPIO_InitTypeDef GPIO_InitStruct;

    SPI_InitTypeDef SPI_InitStruct;

  2. // enable clock for used IO pins

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // connect SPI1 pins to SPI alternate function

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

    // enable peripheral clock

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    /* configure SPI1 in Mode 0

    * CPOL = 0 --> clock is low when idle

    * CPHA = 0 --> data is sampled at the first edge

    */

    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines

    SPI_InitStruct.SPI_Mode = SPI_Mode_Slave; // transmit in master mode, NSS pin has to be always high

    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide

    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle

    SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge

    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // set the NSS management to software

    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first

    SPI_InitStruct.SPI_CRCPolynomial = 7;

    SPI1->CR1 |=0x1000;

    SPI1->CR2 |=0x20;

    SPI_Init(SPI1, &SPI_InitStruct);

  3. SPI_Cmd(SPI1, ENABLE); // enable SPI1

    }

从机发送和接收函数:
  1. void SPI1_Send(uint8_t data){

    SPI1->DR = data; // write data to be transmitted to the SPI data register

    while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete

    }

  2. uint8_t SPI1_Receive(void){

    while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete

    return SPI1->DR; // return received data from SPI data register

    }

从机主函数接收:
  1. while(1){

    if(index_spi==BufferSize){

    index_spi=0;

    printf("%s\n\r",receive_data);

    }

    else{

    receive_data[index_spi]=SPI1_Receive();

    SPI1_Send(receive_data[index_spi]);

    index_spi++;

    }

1. 首先测试两个之间就只是双向发送和接收,接收到的结果会有一位的偏移,比如我发一段字节:Google Inc. is an American multinational 从机收到:lGoogle Inc. is an American multinationa,从机主机都是同时收发。从机收到一个字节就同时发回这个字节。然后主机收到的也是lGoogle Inc. is an American multinationa,不知道这个是不是正常的,有没有大侠能解释下这一位的偏移是怎么回事? 2. 然后加上握手部分,希望主机发完字符串然后发送无用字节并等待回复,从机收完字符串之后收无用字符并同时发出确认字节。 主机主函数发送:
  1. for(index_data=0;index_data

    receive_data[index_data]=SPI1_sendrecv(send_data[index_data]);

    }

    for(j=0;j<4;j++){

    ack_string[j]=SPI1_sendrecv(0x00);

    }

    printf("%s\n\r",receive_data);

    printf("ack string: %s\n\r",ack_string);

从机主函数接收:
  1. char ack_string[4]="GOOD";

    while(1){

    if(index_spi==BufferSize){

    index_spi=0;

    printf("%s\n\r",receive_data);

    for(i=0;i<4;i++){

    SPI1_Receive();

    SPI1_Send(ack_string[i]);

    }

    }

    else{

    receive_data[index_spi]=SPI1_Receive();

    SPI1_Send(receive_data[index_spi]);

    index_spi++;

    }

    }

主机发送Google Inc. is an American multinational, 从机收到gle Inc. is an American multinational 主机收到的字符串GOODgle Inc. is an American multinationa 收到的ack string是ack string: l 所以结果好像是从机回复的ack主机都在下一次收数据的时候才收到了。这个也很难理解,而且我试过了不管ack设多长,主机都是后面一步才在一串数据的开头收到这段ack。

回复评论 (3)

SPI数据通信实际上就是两个串行移位寄存器首尾环境在一起。数据发送同步于数据接收,也就是发完一个字节的同时也收到了一个字节。
主机的发送是启动数据传输,而从机的发送函数实际上是为下一次数据接收时准备发送数据。
你的程序是从机接收到一个字节,再返回发送,所以返回数据将必然将后移一个字节。
要使环回正确。主机应当丢弃第一次发送时收到的第一个字节。所有数据发送完成后再发一个无效数据,读取对端返回的最后一个字节。
点赞  2013-4-17 12:01
楼上说的很有道理。
点赞  2013-4-17 15:26

回复 沙发 xg_qing 的帖子

多谢回复。那这样的话最多也就是一个字节的偏移而已吧。我问的另外一个关于握手的问题怎么解释呢,主机收到的ack回复全部都和后面的数据一起到达了,这个不是一个字节了,而是四个字节。
点赞  2013-4-17 16:36
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复