尊敬的堆栈溢出用户:
我用一个主设备和一个由10个从设备组成的网络构建了一个设备。它们都通过4线spi通信。现在我正在为两个董事会编写程序,他们似乎都不起作用,我没有得到预期的回应。
我有一个主板,和10个相同的从主板。协议很简单,就像spi一样,任何事务都由主设备发起,并发送命令。然后,所选从机接收一个预先调整的命令,将忙标志引脚设置为高,并检查它是否有效。解析命令后,将释放busy bin,如果命令有效,则向master发送与接收到的字节相同的字节,否则将发送错误标记。之后,执行任何必要的数据交换。我试过将IO配置为常规端口F及其替代功能,也试过在每次事务后重置SPI外围设备,但似乎没有任何效果。
这就是我得到的:
https://imgur.com/a/MICEx2f
频道分别从顶部开始:
mosi,miso,clk和busy flag。不管怎样,我都得不到奴隶的回应。该命令被正确解释(来自uart的调试数据),但是没有返回任何内容。
这是从设备代码的spi部分:

uint8_t spi_sendrecv(uint8_t byte)
{
    // poczekaj az bufor nadawczy bedzie wolny
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, byte);

    // poczekaj na dane w buforze odbiorczym
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    return SPI_I2S_ReceiveData(SPI1);
}

uint8_t SPI_get_cmd_ack(void)
{
    uint8_t cmd;
    uint8_t valid_flag;

    //In cas if the BF pin was left high
    BF_OUT_low();

    //Let's wait for some data
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    cmd = SPI_I2S_ReceiveData(SPI1);
    //cmd = SPI_get_command();

    //Check the cmd
    BF_OUT_high();
    valid_flag = SPI_check_for_valid_cmd(cmd);
    //SPI_reset_flush();
    BF_OUT_low();

    if(valid_flag == CMD_RET_STATUS_VALID)
    {
        spi_sendrecv(cmd);
        return cmd;
    }
    else
    {
        spi_sendrecv(CMD_ERROR);
        return CMD_ERROR;
    }
}

这是主要部分:
//Sends a command to a slave device
//Param1: slave device no, from 0  to 9
//Param2: command to send
//Retval: command send success or failure:
//DATA_TRANSFER_OK or DATA_TRANSFER_ERR
uint8_t SPI_send_command(uint8_t slave_no, uint8_t cmd)
{
    uint8_t cnt = 0;
    uint8_t rx_cmd;

    //SPI_reset();

    //Select the correct slave
    SPI_select_slave(0);
    delay_ms(0);
    SPI_select_slave(slave_no);
    delay_ms(0);
    //Transmit the cmd
    SPI_sendrecv(cmd);
    //SPI_reset();
     //Wait for the busy flag indication
     while(SPI_get_busy_flag(slave_no) == Bit_RESET)
     {
         if(cnt < SPI_RETRY_COUNT)
         {
             ++cnt;
             delay_ms(1);
         }
         else
        {
             SPI_select_slave(0);
             return DATA_TRANSFER_ERR;
        }
     }
     //Same for the busy flag on:
     while (SPI_get_busy_flag(slave_no) == Bit_SET)
     {
         if(cnt < SPI_RETRY_COUNT)
         {
             ++cnt;
             delay_ms(1);
         }
         else
         {
             SPI_select_slave(0);
             return DATA_TRANSFER_ERR;
         }
     }

     rx_cmd = SPI_sendrecv(0);

     //SPI_reset();

     if(rx_cmd == cmd) return DATA_TRANSFER_OK;
     else return DATA_TRANSFER_ERR;
}

下面是代码的初始化部分,slave和master分别是:
void SPI_init(void)
{
    GPIO_InitTypeDef SPI_GPIO;
    SPI_InitTypeDef SPI;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    //GPIOA5 SCK
    //GPIOA6 MISO
    //GPIOA7 MOSI
    SPI_GPIO.GPIO_Mode = GPIO_Mode_AF;
    SPI_GPIO.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    SPI_GPIO.GPIO_PuPd = GPIO_PuPd_DOWN;
    SPI_GPIO.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOA, &SPI_GPIO);

    SPI_GPIO.GPIO_Pin = GPIO_Pin_15;
    SPI_GPIO.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &SPI_GPIO);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI1);

    //Busy flag
    SPI_GPIO.GPIO_Mode = GPIO_Mode_OUT;
    SPI_GPIO.GPIO_OType = GPIO_OType_PP;
    SPI_GPIO.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOC, &SPI_GPIO);

    /*SPI_GPIO.GPIO_Mode = GPIO_Mode_IN;
    SPI_GPIO.GPIO_PuPd = GPIO_PuPd_UP;
    SPI_GPIO.GPIO_Pin = GPIO_Pin_15;
    GPIO_Init(GPIOA, &SPI_GPIO);*/

    SPI.SPI_CPHA = SPI_CPHA_1Edge;
    SPI.SPI_CPOL = SPI_CPOL_Low;
    SPI.SPI_DataSize = SPI_DataSize_8b;
    SPI.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI.SPI_Mode = SPI_Mode_Slave;
    SPI.SPI_NSS = SPI_NSS_Hard;

    SPI_Init(SPI1, &SPI);

    SPI_Cmd(SPI1, ENABLE);

    SPI_aux_tim_conf();
}

static void SPI_IO_conf(void)
{
    //Struct
    GPIO_InitTypeDef SPI_IO;

    //CLK
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE, ENABLE);

    //Conf
    SPI_IO.GPIO_Mode = GPIO_Mode_AF;
    //5 - SCK, 6 - MISO, 7- MOSI
    SPI_IO.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_6;
    SPI_IO.GPIO_PuPd = GPIO_PuPd_DOWN;
    SPI_IO.GPIO_OType = GPIO_OType_PP;
    SPI_IO.GPIO_Speed = GPIO_Speed_25MHz;

    //Init
    GPIO_Init(GPIOA, &SPI_IO);

    //Connect to SPI periph
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);


    //For busy flag checking
    SPI_IO.GPIO_Mode = GPIO_Mode_IN;
    SPI_IO.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 |GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    SPI_IO.GPIO_PuPd = GPIO_PuPd_DOWN;
    SPI_IO.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_Init(GPIOE, &SPI_IO);

    SPI_IO.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOB, &SPI_IO);
}

static void SPI_periph_conf(void)
{
    //Struct
    SPI_InitTypeDef SPI_conf;

    //CLK
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    //Conf
    //SysClk = 84000000
    //84/64 = 1,3125MHz
    SPI_conf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
    SPI_conf.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_conf.SPI_CPOL = SPI_CPOL_Low;
    //SPI_conf.SPI_CRCPolynomial =
    SPI_conf.SPI_DataSize = SPI_DataSize_8b;
    SPI_conf.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_conf.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_conf.SPI_Mode = SPI_Mode_Master;
    SPI_conf.SPI_NSS = SPI_NSS_Soft;

    //Conf, enable
    SPI_Init(SPI1, &SPI_conf);

    SPI_Cmd(SPI1, ENABLE);
    //SPI_Cmd(SPI1, DISABLE);
}

从示波图上可以看到,从机没有响应,预期响应与主机在前一个周期发送的命令相同。例如,我发送一个0x01存在命令,从机应该用相同的字节响应,之后,应该发生任何其他交换,这些交换尚未实现。
谨致问候,马雷克

最佳答案

从你的图片上看,发送数据后clk保持在低位。在spi中,主人是时钟的唯一管理者。
从AA>
忙标志
此bsy标志由硬件设置和清除(写入此标志无效)。bsy标志表示spi的通信层的状态。
设置bsy时,表示spi正忙着通信。在主模式/双向接收模式(mstr=1和bdm=1和bdoe=0)中有一个例外,在接收期间bsy标志保持低。
如果软件要禁用SPI并进入暂停模式(或禁用外围时钟),则BSY标志可用于检测传输结束。这样可以避免破坏最后一次传输。为此,必须严格遵守以下程序。
bsy标志对于避免多主机系统中的写入冲突也很有用。
在传输开始时设置bsy标志,除了主模式/双向接收模式(mstr=1和bdm=1和bdoe=0)。
已清除:
传输完成时(如果通信是连续的,则在主模式下除外)
当发生主模式故障(modf=1)时,SPI被禁用
当通信不连续时,每次通信之间的bsy标志是低的。
当通信持续时:
在主模式下,bsy标志在所有传输期间都保持高
在从模式下,每次传输之间的一个spi时钟周期内bsy标志变低
注意:不要使用bsy标志来处理每次数据传输或接收。最好改用txe和rxne标志
所以我认为你在发送数据后在主机中等待busy标志可以无限期锁定。试试这个(代码使用普通的cmsis,但应该可以理解):

GPIOB->BSRR |= GPIO_BSRR_BR6; //slave select
while(! (SPI1->SR & SPI_SR_TXE)); //wait for Tx buffer empty
SPI1->DR = 0x01; //send 0x01
while(! (SPI1->SR & SPI_SR_RXNE)); //wait for Rx buffer not empty (receive 0x0 sent by the slave during our sending 0x01 since it's 4-wire SPI)
uint8_t tmp = SPI1->DR; //we don't need that value, but need to read DR in order to reset RXNE flag
SPI1->DR = 0x0; //we need to trigger send in order to receive
while(! (SPI1->SR & SPI_SR_RXNE)); //wait for Rx buffer not empty (our response)
response = SPI1->DR;
while(SPI1->SR & SPI_SR_BSY); //now we can wait for SPI to end communications
GPIOB->BSRR |= GPIO_BSRR_BS6; //slave deselect

关于c - STM32,主设备和从设备彼此不响应,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55587289/

10-09 08:43