首页 > 解决方案 > Arduino 未注册来自 STM32F407 的 SPI 传输

问题描述

编辑/解决:问题最终是我在 Arduino 代码中的 Serial.print 语句,这些语句减慢了实际通信代码的执行速度。基本上,Arduino 在 STM 板完成发送后接收字节,所以它只注册 'd'/100。

我目前正在参加在线课程,但其中一个练习存在问题。这个练习看起来很简单,但我似乎无法让一切正常工作。练习是从主控 MCU STM32F407 向 Arduino Uno 板发送一个字符串,然后应该打印消息及其长度。

Arduino 板似乎注册了 SS,但不会打印任何内容、打印不完整/不正确的消息(例如“hello vorl”)或打印乱码。经过一些调试后,我发现我错误地设置了我的 CPOL 和 CPHA 寄存器,但是,现在它不会打印任何接近“Hello world”的内容。经过更多调试,似乎 Arduino 卡在了它的 SPI_SlaveReceive 函数中。STM 的 SPI 代码设计为首先发送消息的长度,然后发送实际的消息。据我所知,Arduino 似乎没有为第一次传输注册正确的长度,这弄乱了应该获取实际消息的 SPI_SlaveReceive 调用的循环。

我是嵌入式新手,并且一直在尝试自己学习。我觉得我可能缺少一些基本的东西,但不知道。我也觉得代码设计得很糟糕,但我试图坚持课程(STM代码是按照指南“编写”的,而arduino代码只是提供了)。我将在下面发布代码,但我什至会欣赏关于可能出错/如何调试的想法。在所有内容下方,我还将发布一些错误记录。

这也是我的第一篇 stackoverflow 帖子,所以如果我需要添加(或删除)任何内容,请告诉我。谢谢!

更新:我认为这可能与时钟速度有关。我尝试在调试器中再次运行代码,发现如果我在修改 SPI 的数据寄存器的代码上放置一个断点,我就能够成功发送数据。看起来 SPI 发送数据的速度可能比 Arduino 可以处理的更快。如果我单步执行发送消息“Hello world”长度的代码,那么我可以看到 Arduino 成功接收到 11。如果我继续单步执行 pSPIx->DR = *pTxBuffer; 第二次调用SPI_SendData的指令,我可以成功发送消息。但是,如果在发送长度后,我会尝试一步完成对 SPI_SendData 的第二次调用。arduino 没有注册整个字符串。我尝试将 SPI 预标量修改为更大的值,这似乎有帮助。ie arduino 能够输出更多有效字符(导致“hellod”)。然而,这让我感到困惑,因为控制 SPI2 的 APB1 的最大频率为 42MHz。我发现给我最好的结果的预标量值是 7,这意味着 PCLK 除以 256,如果我正确地考虑这一点,最多可以得到 164 MHz 的频率。根据 Ardunio 的规格,处理此通信应该没有问题。我想我可能有一个问题是比特的发送频率是多少?也许我的 SPI_SendData 函数不能正常工作?然而,这让我感到困惑,因为控制 SPI2 的 APB1 的最大频率为 42MHz。我发现给我最好的结果的预标量值是 7,这意味着 PCLK 除以 256,如果我正确地考虑这一点,最多可以得到 164 MHz 的频率。根据 Ardunio 的规格,处理此通信应该没有问题。我想我可能有一个问题是比特的发送频率是多少?也许我的 SPI_SendData 函数不能正常工作?然而,这让我感到困惑,因为控制 SPI2 的 APB1 的最大频率为 42MHz。我发现给我最好的结果的预标量值是 7,这意味着 PCLK 除以 256,如果我正确地考虑这一点,最多可以得到 164 MHz 的频率。根据 Ardunio 的规格,处理此通信应该没有问题。我想我可能有一个问题是比特的发送频率是多少?也许我的 SPI_SendData 函数不能正常工作?我想我可能有一个问题是比特的发送频率是多少?也许我的 SPI_SendData 函数不能正常工作?我想我可能有一个问题是比特的发送频率是多少?也许我的 SPI_SendData 函数不能正常工作?

其他详情:

记录:

16:01:42.461 -> Slave Initialized
16:01:42.494 -> Slave waiting for ss to go low
16:01:45.500 -> slave selected
16:01:45.500 -> Waiting to receive length
16:01:45.534 -> Length: 68
16:01:47.520 -> Received: 
16:01:47.554 -> Received: d
16:01:48.968 -> Received: 
16:01:48.968 -> Received: d
16:01:49.858 -> Received: 
16:01:49.858 -> Received: d
16:01:50.499 -> Received: 
16:01:50.499 -> Received: d
16:01:51.137 -> Received: 
16:01:51.137 -> Received: d
16:01:51.707 -> Received: 
16:01:51.741 -> Received: d
16:01:52.244 -> Received: 
16:01:52.277 -> Received: d
16:01:52.782 -> Received: 
16:01:52.782 -> Received: d
16:01:53.360 -> Received: 
16:01:53.393 -> Received: d
16:01:53.866 -> Received: 
16:01:53.899 -> Received: d
16:01:54.441 -> Received: 
16:01:54.441 -> Received: d
16:01:54.946 -> Received: 
16:01:54.980 -> Received: d
16:01:55.484 -> Received: 
16:01:55.518 -> Received: d
16:01:55.994 -> Received: 
16:01:56.027 -> Received: d
16:01:56.599 -> Received: 
16:01:56.599 -> Received: d
16:01:57.105 -> Received: 
16:01:57.138 -> Received: `
16:01:57.609 -> Received: 
16:01:57.644 -> Received: d
16:01:58.085 -> Received: 
16:01:58.118 -> Received: d
16:01:58.622 -> Received: 
16:01:58.622 -> Received: d
16:01:59.128 -> Received: 
16:01:59.161 -> Received: d
16:01:59.676 -> Received: 
16:01:59.676 -> Received: d
16:02:00.146 -> Received: 
16:02:00.180 -> Received: d
16:02:00.654 -> Received: 
16:02:00.654 -> Received: d
16:02:01.127 -> Received: 
16:02:01.127 -> Received: d
16:02:01.634 -> Received: 
16:02:01.668 -> Received: d
16:02:02.105 -> Received: 
16:02:02.139 -> Received: d
16:02:02.582 -> Received: 
16:02:02.582 -> Received: d
16:02:03.052 -> Received: 
16:02:03.052 -> Received: d
16:02:03.729 -> Received: 
16:02:03.729 -> Received: d
16:02:04.236 -> Received: 
16:02:04.236 -> Received: d
16:02:04.774 -> Received: 
16:02:04.774 -> Received: d
16:02:05.336 -> Received: 
16:02:05.336 -> Received: d
16:02:05.947 -> Received: 
16:02:05.980 -> Received: d
16:02:06.485 -> Received: 
16:02:06.485 -> Received: d
16:02:06.518 -> done receiving word
16:02:06.518 -> Rcvd:
16:02:06.553 -> ddddddddddddddd`dddddddddddddddddd
16:02:06.620 -> Length:68
16:02:06.620 -> Slave deselected
16:02:06.654 -> Slave waiting for ss to go low
16:02:07.025 -> slave selected
16:02:07.058 -> Waiting to receive length
16:02:07.092 -> Length: 100

Arduino代码:

/* SPI Slave Demo
 *
 * SPI pin numbers:
 * SCK   13  // Serial Clock.
 * MISO  12  // Master In Slave Out.
 * MOSI  11  // Master Out Slave In.
 * SS    10  // Slave Select . Arduino SPI pins respond only if SS pulled low by the master
 *

 */
#include <SPI.h>
#include<stdint.h>
#define SPI_SCK 13
#define SPI_MISO 12
#define SPI_MOSI 11
#define SPI_SS 10

char dataBuff[500];
//Initialize SPI slave.
void SPI_SlaveInit(void) 
{ 
 #if 0 
  // Initialize SPI pins.
  pinMode(SPI_SCK, INPUT);
  pinMode(SPI_MOSI, INPUT);
  pinMode(SPI_MISO, OUTPUT);
  pinMode(SPI_SS, INPUT);

  // Enable SPI as slave.
  SPCR = (1 << SPE);
 #endif 
   // Initialize SPI pins.
  pinMode(SCK, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT);
  //make SPI as slave

  // Enable SPI as slave.
  SPCR = (1 << SPE);

}

//This function returns SPDR Contents 
uint8_t SPI_SlaveReceive(void)
{
  /* Wait for reception complete */
  while(!(SPSR & (1<<SPIF)));
  /* Return Data Register */
  return SPDR;
}


//sends one byte of data 
void SPI_SlaveTransmit(char data)
{
  /* Start transmission */
  SPDR = data;

  /* Wait for transmission complete */
  while(!(SPSR & (1<<SPIF)));
}


// The setup() function runs right after reset.
void setup() 
{
  // Initialize serial communication 
  Serial.begin(9600);

  // Initialize SPI Slave.
  SPI_SlaveInit();

  Serial.println("Slave Initialized");
}
 uint16_t dataLen = 0;
  uint32_t i = 0;
// The loop function runs continuously after setup().
void loop() 
{



  Serial.println("Slave waiting for ss to go low");
  while(digitalRead(SS) );
  Serial.println("slave selected");

 //  Serial.println("start");

  //1. read the length  
//  dataLen = (uint16_t)( SPI_SlaveReceive() | (SPI_SlaveReceive() << 8) );
  //Serial.println(String(dataLen,HEX));
 i = 0;
  Serial. println("Waiting to receive length");
  dataLen = SPI_SlaveReceive();
  for(i = 0 ; i < dataLen ; i++ )
  {
    dataBuff[i] =  SPI_SlaveReceive();
    Serial.print("Received: ");
    Serial.println(dataBuff[i]);
  }
  Serial.println("done receiving word");

  //  Serial.println(String(i,HEX));
  dataBuff[i] = '\0';

  Serial.println("Rcvd:");
  Serial.println(dataBuff);
  Serial.print("Length:");
  Serial.println(dataLen);

  while(!digitalRead(SS));
  Serial.println("Slave deselected");


}

主要STM代码:

#include <string.h>
#include "stm32f407xx.h"


/*
 * PB15 --> SPI2_MOSI
 * PB14 --> SPI2_MISO
 * PB13 --> SPI2_SCLK
 * PB12 --> SPI2_NSS
 * ALT Function mode: 5
 */

void SPI_GPIO_Setup(void);
void GPIO_ButtonInit(void);
void SPI_Setup(void);

void delay(int time){
    for(uint32_t i=0; i<time; i++);
}

int main(void) {

    char userData[] = "Hello world";

    //initizalize button
    GPIO_ButtonInit();

    //This function is used to initialize the gpio pins to behave as spi pins
    SPI_GPIO_Setup();

    //This function is used to initialize the SPI peripheral
    SPI_Setup();

    //this makes NSS signal internally high and avoids MODF error
    //NOTE: This should be taken care of in my SPI_Init function
//  SPI_SSIConfig(SPI2, ENABLE);

    //SSOE to 1 does NSS output enable
    //I don't want to enable this in this way, but it is more simple due to the code design
    //i.e. (using shifts instead of masks for registers)
    SPI_SSOEConfig(SPI2, ENABLE);

    while(1){
        //wait for button to be pressed
        while(! GPIO_ReadFromInputPin(GPIOA, GPIO_PIN_0));

        delay(250000); //used for button debouncing

        //enable the SPI2 peripheral --- according to generated code, this seems to be done in the transmit function
        // I a SET_BIT macro in the transmit function if SPI isn't enabled, make sure to test this
        SPI_PeripheralControl(SPI2, ENABLE);

        //first send the length of data (Arduino expects this as 1 byte)
        uint8_t dataLen = strlen(userData);
        SPI_SendData(SPI2, &dataLen, 1);

        //send data
        SPI_SendData(SPI2, (uint8_t*)userData, dataLen);

        //confirm the SPI is not busy
        while(SPI_GetFlagStatus(SPI2, SPI_BSY_FLAG));

        //disable the SPI2 peripheral --- according to Generated code, this seems to be done in abort functions
        SPI_PeripheralControl(SPI2, DISABLE);
    }

    return 0;
}

void SPI_GPIO_Setup(void) {

    GPIO_Handle_t SPIpins;

    SPIpins.pGPIOx = GPIOB;
    SPIpins.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_ALTFN;
    SPIpins.GPIO_PinConfig.GPIO_PinAltFunMode = 5;
    SPIpins.GPIO_PinConfig.GPIO_PinOPType = GPIO_OPTYPE_PP;
    SPIpins.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PU;
    SPIpins.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_FAST;

    //MOSI
    SPIpins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_15;
    GPIO_Init(&SPIpins);


    //MISO
//  SPIpins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_14;
//  GPIO_Init(&SPIpins);

    //SCLK
    SPIpins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_13;
    GPIO_Init(&SPIpins);

    //NSS
    SPIpins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_12;
    GPIO_Init(&SPIpins);


}
void GPIO_ButtonInit(void){
    GPIO_Handle_t GpioBtn;

    // configure button
    //Set up PA0 to be an input for the button press
    GpioBtn.pGPIOx = GPIOA;
    GpioBtn.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_0;
    GpioBtn.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_IN;
    GpioBtn.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_FAST;
    GpioBtn.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
    GPIO_Init(&GpioBtn);
}
void SPI_Setup(void){
    SPI_Handle_t hSPI;

    hSPI.SPIx = SPI2;
    hSPI.SPIConfig.SPI_BusConfig = SPI_BUS_CONFIG_FD;
    hSPI.SPIConfig.SPI_DeviceMode = SPI_DEVICE_MODE_MASTER;
    hSPI.SPIConfig.SPI_SclkSpeed = SPI_SCLK_SPEED_DIV8; //generate SCLK of 2 MHz
    hSPI.SPIConfig.SPI_DFF = SPI_DFF_8BITS;
    hSPI.SPIConfig.SPI_CPOL = SPI_CPOL_LOW;
    hSPI.SPIConfig.SPI_CPHA = SPI_CPHA_LOW;
    hSPI.SPIConfig.SPI_SSM = SPI_SSM_DI; //Hardware slave management disabled for NSS pin

    SPI_Init(&hSPI);
}

SPI驱动代码:

    /*
 * stm32f407xx_spi_driver.c
 *
 *  Created on: Oct 17, 2019
 *      Author: pigmo
 */

#include "stm32f407xx_spi_driver.h"

/**************************************************************************
 *                  APIs supported by this driver
 * For more information about these APIs check the function description
 **************************************************************************/
/*
 * Peripheral clock setup
 */

/******************************************************
 * @fn                  - SPI_PeriClockControl
 *
 * @brief               - Enables or disables peripheral clock for the given SPI port
 *
 * @param[in]           - base address of SPI peripheral
 * @param[in]           - ENABLE or DISABLE macros
 *
 * @return              - none
 *
 * @Note                - SPI4 is reserved and won't be affected by this function
 */
void SPI_PeriClockControl(SPI_RegDef_t* pSPIx, uint8_t enOrDi){
    if(enOrDi == ENABLE){
            if(pSPIx == SPI1){
                SPI1_PCLK_EN();
            } else if (pSPIx == SPI2){
                SPI2_PCLK_EN();
            } else if (pSPIx == SPI3){
                SPI3_PCLK_EN();
            }
        } else {
            if(pSPIx == SPI1){
                SPI1_PCLK_DI();
            } else if (pSPIx == SPI2){
                SPI2_PCLK_DI();
            } else if (pSPIx == SPI3){
                SPI3_PCLK_DI();
            }
        }
}

/*
 * Init and De-init
 */

/******************************************************
 * @fn                  - SPI_Init
 *
 * @brief               - Initializes a given GPIO peripheral with given configurations
 *
 * @param[in]           - Struct holding base address and desired configurations of SPI peripheral
 *
 * @return              - none
 *
 * @Note                - I don't like the way this is done, but I'm doing it to be consistent with the course
 *                          Instead, I think the SPIConfig should hold masks, not enum type values
 */
void SPI_Init(SPI_Handle_t *pSPIHandle){

    //enable the spi clock
    SPI_PeriClockControl(pSPIHandle->SPIx, ENABLE);

    //disable the SPI (concept taken from STM generated code)
    SPI_PeripheralControl(pSPIHandle->SPIx, DISABLE);

    //first configure the SPI CR1 register
    uint32_t tempReg = 0;

    //1. configure the device mode
    if(pSPIHandle->SPIConfig.SPI_DeviceMode == SPI_DEVICE_MODE_MASTER){
        // if the device is master mode, then the SSI must also be 1 to avoid an error (unless Multi master?)
        // this is only true if SSM is enabled, can we keep this functionality even is SSM is disabled?
        // based on stm generated code, the SSI stays enabled for SSM enabled and disabled
        tempReg |= pSPIHandle->SPIConfig.SPI_DeviceMode << SPI_CR1_MSTR;
        tempReg |= (1 << SPI_CR1_SSI); // this should probably be done in another way
    } else {
        tempReg |= pSPIHandle->SPIConfig.SPI_DeviceMode << SPI_CR1_MSTR;
    }

    //2. configure the bus config
    if(pSPIHandle->SPIConfig.SPI_BusConfig == SPI_BUS_CONFIG_FD){
        //bdi should be cleared
        tempReg &= ~(1 << SPI_CR1_BIDIMODE);
    } else if(pSPIHandle->SPIConfig.SPI_BusConfig == SPI_BUS_CONFIG_HD){
        //bdi should be set
        tempReg |= ~(1 << SPI_CR1_BIDIMODE);
    } else {
        //bdi should be cleared
        tempReg &= ~(1 << SPI_CR1_BIDIMODE);
        //RXONLY should be set
        tempReg |= (1 << SPI_CR1_RXONLY);
    }

    //3. configure the clock speed
    tempReg |= (pSPIHandle->SPIConfig.SPI_SclkSpeed << SPI_CR1_BR);

    //4. configure the Data frame format
    tempReg |= (pSPIHandle->SPIConfig.SPI_DFF << SPI_CR1_DFF);

    //5. configure the clock polarity
    tempReg |= (pSPIHandle->SPIConfig.SPI_CPOL << SPI_CR1_CPOL);

    //6. configure the clock phase
    tempReg |= (pSPIHandle->SPIConfig.SPI_CPHA << SPI_CR1_CPHA);

    //7. determine hardware or software slave management
    tempReg |= (pSPIHandle->SPIConfig.SPI_SSM << SPI_CR1_SSM);

    pSPIHandle->SPIx->CR1 = tempReg;
}

/******************************************************
 * @fn                  - SPI_DeInit
 *
 * @brief               - Deinitializes a given SPI periphal and resets register
 *
 * @param[in]           - base address of SPI peripheral
 *
 * @return              - none
 *
 * @Note                - none
 */
void SPI_DeInit(SPI_RegDef_t* pSPIx){
    if(pSPIx == SPI1){
        SPI1_REG_RESET();
    } else if (pSPIx == SPI2){
        SPI2_REG_RESET();
    } else if (pSPIx == SPI3){
        SPI3_REG_RESET();
    }
}

/*
 * Data send and receive
 */

uint8_t SPI_GetFlagStatus(SPI_RegDef_t* pSPIx, uint32_t flag){
    if(pSPIx->SR & flag){
        return SET;
    } else {
        return RESET;
    }
}

/******************************************************
 * @fn                  - SPI_SendData
 *
 * @brief               - sends data of length len to transmit buffer
 *
 * @param[in]           - base address of SPI peripheral
 * @param[in]           - address of Tx buffer
 * @param[in]           - length of data to send
 *
 * @return              - none
 *
 * @Note                - This is a blocking call
 */
//actual code seems much more complex, check that out
void SPI_SendData(SPI_RegDef_t* pSPIx, uint8_t *pTxBuffer, uint32_t len){
    //if SPi is not enabled, then enable it
    if((pSPIx->CR1 & (1 << SPI_CR1_SPE)) != (1 << SPI_CR1_SPE)){
        SET_BIT(pSPIx->CR1, (1 << SPI_CR1_SPE)); // this is repetitive, should just have a mask,
    }

    while(len > 0) {
        //1. Wait until Tx is empty
        while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG) ==  RESET);

        //2. Check DFF in CR1
        if (pSPIx->CR1 & (1 << SPI_CR1_DFF) ) {
            //16 bit dff
            //3. load data into DR
            pSPIx->DR = *((uint16_t*)pTxBuffer);
            len--;
            len--;
            (uint16_t*)pTxBuffer++;
        } else {
            //8 bit dff
            //3. load data into DR
            pSPIx->DR = *pTxBuffer;
            len--;
            pTxBuffer++;
        }

    }
}

/******************************************************
 * @fn                  - SPI_ReceiveData
 *
 * @brief               - Receives data of length len to Receive buffer
 *
 * @param[in]           - base address of SPI peripheral
 * @param[in]           - address of Rx buffer
 * @param[in]           - length of data to Receive
 *
 * @return              - none
 *
 * @Note                - none
 */
void SPI_ReceiveData(SPI_RegDef_t* pSPIx, uint8_t *pRxBuffer, uint32_t len){

}

/*
 * IRQ configuration and handling
 */

/******************************************************
 * @fn                  - SPI_IRQITConfig
 *
 * @brief               - enables or disables a SPI peripherals IRQ functionality
 *
 * @param[in]           - IRQ number of SPI peripheral
 * @param[in]           - ENABLE or DISABLE macros
 *
 * @return              - none
 *
 * @Note                - none
 */
void SPI_IRQInterruptConfig(uint8_t IRQNumber, uint8_t enOrDi){

}

/******************************************************
 * @fn                  - SPI_IRQPriorityConfig
 *
 * @brief               - sets the priority for a given IRQ number
 *
 * @param[in]           - IRQ priority of SPI peripheral
 * @param[in]           - IRQ number of SPI peripheral
 *
 * @return              - none
 *
 * @Note                - modifies the NVIC peripheral
 */
void SPI_IRQPriorityConfig(uint8_t IRQPriority, uint8_t IRQNumber){

}

/******************************************************
 * @fn                  - SPI_IRQHandling
 *
 * @brief               - deals with a interrupt triggered by a SPI pin
 *
 * @param[in]           - Struct holding base address and desired configurations of SPI peripheral
 *
 * @return              - none
 *
 * @Note                - none
 */
void SPI_IRQHandling(SPI_Handle_t *pHandle){

}

/******************************************************
 * @fn                  - SPI_PeripheralControl
 *
 * @brief               - Enables or Disables SPI
 *
 * @param[in]           - Pointer to a SPI register
 *
 * @return              - none
 *
 * @Note                - I'm implementing this in the transmit function
 */
void SPI_PeripheralControl(SPI_RegDef_t *pSPIx, uint8_t enOrDi){
    if(enOrDi == ENABLE){
        pSPIx->CR1 |= (1 << SPI_CR1_SPE);
    } else {
        pSPIx->CR1 &= ~(1 << SPI_CR1_SPE);
    }
}

/******************************************************
 * @fn                  - SPI_SSIConfig
 *
 * @brief               - Sets or Resets SSI bit in SPI CR1 reg
 *
 * @param[in]           - Pointer to a SPI register
 *
 * @return              - none
 *
 * @Note                - This code is used in the course I'm following,
 *                      but I think it is redundant and bad practice. It will not be used.
 *                      Instead, I implemented a check in the SPI init function to enable SSI w/ master
 */
void SPI_SSIConfig(SPI_RegDef_t *pSPIx, uint8_t enOrDi){
    if(enOrDi == ENABLE){
        pSPIx->CR1 |= (1 << SPI_CR1_SSI);
    } else {
        pSPIx->CR1 &= ~(1 << SPI_CR1_SSI);
    }
}

/******************************************************
 * @fn                  - SPI_SSOEConfig
 *
 * @brief               - Sets or Resets SSOE bit in SPI CR2 reg
 *
 * @param[in]           - Pointer to a SPI register
 *
 * @return              - none
 *
 * @Note                - This code is used in the course I'm following,
 *                      but I think it is redundant and bad practice. I will use it bec of consistency
 *                      Otherwise, in the STM generated code, this bit is determine by a NSS value in the init struct
 *                      See: WRITE_REG(hspi->Instance->CR2, (((hspi->Init.NSS >> 16U) & SPI_CR2_SSOE) | hspi->Init.TIMode));
 */
void SPI_SSOEConfig(SPI_RegDef_t *pSPIx, uint8_t enOrDi){
    if(enOrDi == ENABLE){
        pSPIx->CR2 |= (1 << SPI_CR2_SSOE);
    } else {
        pSPIx->CR2 &= ~(1 << SPI_CR2_SSOE);
    }
}

标签: arduinoembeddedstm32spi

解决方案


推荐阅读