stm32f405+drv8303的spi通讯异常

项目简介:stm32f405+drv8303驱动无刷电机

在通过stm32自带spi库函数与drv8303进行配置通讯结果总是异常,无法正确读回配置ControlRegister1和ControlRegister2.现将代码附上分析原因。

以下是drv8303的代码:

#ifndef __DRV8303_H
#define __DRV8303_H
#include "main.h"
#include "spi.h"
typedef uint8_t   DRV8303_8BitsType;
typedef uint16_t  DRV8303_16BitsType;
#define DRV8303_NUM 1   /* DRV8303数量 */
#define DRV8303_CS()   HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET)   /* 片选 */
#define DRV8303_NCS()  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET)     /* 取消片选 */
/* ADDRESS 0x02 */
/* 栅极电流大小设置,设定了DRV8303驱动MOS管栅极的引脚的输入输出电流限制 */
/* 引脚:GH_A,GH_B,GH_C,GL_A,GL_B,GL_C */
/* 该设置影响了栅极驱动电流,从而影响MOS管栅极的输入寄生电容充电时间,影响开关速度 */
/* GATE_DRIVE_PEAK_CURRENT_1A7 : 最大输出电流1.7A  最大输入电流2.3A */
/* GATE_DRIVE_PEAK_CURRENT_0A7 : 最大输出电流0.7A  最大输入电流1.0A */
/* GATE_DRIVE_PEAK_CURRENT_0A25: 最大输出电流0.25A 最大输入电流0.5A */
/* 默认为0 */
typedef enum{
    GATE_DRIVE_PEAK_CURRENT_1A7 = 0,
    GATE_DRIVE_PEAK_CURRENT_0A7,
    GATE_DRIVE_PEAK_CURRENT_0A25
} drv8303_gate_current_e;

/* 三相PWM控制模式 */
/* 三相栅极驱动可以提供30mA的平均驱动电流 */ 
/* 当所选的MOSFET器件栅极寄生电容为25nC时支持最大200KHz的开关频率 */
/* PWM6_INPUTS_MODE : 6路PWM波控制,由前级控制器负责高低半桥的开关 */
/* PWM3_INPUTS_MODE : 3路PWM波控制,由前级控制器负责高半桥的开关,DRV8303自动对低半桥执行反逻辑控制 */
/* 默认为0 */
typedef enum{
    PWM6_INPUTS_MODE = 0,
    PWM3_INPUTS_MODE
} drv8303_pwm_mode_e;

/* 过流保护(Overcurrent Protection)和上报(Reporting)模式设置 */
/* 为了保护功率级不因电流过大而损坏,在DRV8303中实现了VDS传感电路。 */
/* 在超过电压阈值时触发过流保护功能。电压阈值是通过SPI寄存器编程的。 */
/* 过流保护只能作为一种保护方案使用;它不能作为一个精确的电流调节方案。 VDS行程点的跨通道公差可达20%。 */
/* I = U / R_DS(ON) 过流阈值为电压阈值除以MOSFET导通电阻 */
/* CURRENT_LIMIT : 电流限流模式,过流时限制电流但并不关闭设备,过流信息从nOCTW引脚和内部寄存器上报 */
/* OOC_LATCH_SHUTDOWNC : 过流锁存关闭模式,过流时关闭对应的半桥MOS,过流信息从nFault引脚和内部寄存器上报 */
/* 此时需要对寄存器gate_reset位写1或者在EN_GATE引脚输出reset复位脉冲进行状态复位,恢复控制 */
/* REPORT_ONLY : 只上报模式,过流时不作处理,只从nOCTW引脚和内部状态寄存器上报过流信息 */
/* OC_DISABLE : 关闭过流检测*/
/* 默认为0 */
typedef enum{
    CURRENT_LIMIT = 0,
    OC_LATCH_SHUTDOWN,
    REPORT_ONLY,
    OC_DISABLE
} drv8303_ocp_mode_e;

/* 过压阈值 */
/* 过流检测通过检测Vds实现,即漏源电压。漏源电流等于漏源电压除以MOS管导通电阻 */
/* 因此,I = U / R_DS(ON) 。其中R_DS(ON)为MOSFET导通电阻 */
/* 例如:对于6.5mohm导通电阻的MOSFET,设计过电流为20A,则电压阈值为20A x 0.0065 = 0.13V */
/* 特别的,对于1.679V以上的电压阈值,仅限在工作电压大于8V时可以被设置 */
typedef enum{
    OC_0V060 = 0,
    OC_0V068, OC_0V076, OC_0V086, OC_0V097, OC_0V109, OC_0V123, 
    OC_0V138, OC_0V155, OC_0V175, OC_0V197, OC_0V222, OC_0V250, 
    OC_0V282, OC_0V317, OC_0V358, OC_0V403, OC_0V454, OC_0V511, 
    OC_0V576, OC_0V648, OC_0V730, OC_0V822, OC_0V926, OC_1V043, 
    OC_1V175, OC_1V324, OC_1V491, OC_1V679, OC_1V892, OC_2V131, OC_2V400
} drv8303_oc_adj_set_e;

/* ADDRESS 0x03 */

/* 错误上报模式设置 */
/* REPORT_OT_AND_nOCTW : 同时在状态寄存器和nOCTW引脚上报信息 */
/* REPORT_OT_ONLY : 只在状态寄存器上报 */
/* REPORT_OC_ONLY : 只在nOCTW引脚上报 */
/* 默认为0 */
typedef enum{
    REPORT_OT_AND_nOCTW = 0,
    REPORT_OT_ONLY,
    REPORT_OC_ONLY
} drv8303_octw_mode_e;

/* 电流检测放大倍数 */
/* 电流检测放大电路的放大倍数设置 */
/* GAIN_10 : 放大倍数为10 */
/* GAIN_20 : 放大倍数为20 */
/* GAIN_40 : 放大倍数为40 */
/* GAIN_80 : 放大倍数为80 */
/* 例: 设置放大倍数为GAIN_40,电机A相电流10A,采样电阻1mohm,电阻两端电压0.01V,则采样电压0.4V*/
/* 默认为0 */
typedef enum{
    GAIN_10 = 0,
    GAIN_20,
    GAIN_40,
    GAIN_80
} drv8303_gain_e;

/* 电流限流的控制模式设置 */
/* 该设置项只在 过流保护模式设置 被设置为 电流限流模式 时有效*/
/* CYCLE_BY_CYCLE : 逐周期模式,检测到过流时关闭MOSFET直到下一个周期*/
/* OFF_TIME : 倒计时模式,检测到过流时关闭64us,如果另一个MOSFET又出现过流则复位倒计时 */
/* 默认为0 */
typedef enum{
    CYCLE_BY_CYCLE = 0,
    OFF_TIME
} drv8303_oc_toff_e;
typedef struct{
    drv8303_gate_current_e  gate_current;
    drv8303_pwm_mode_e      pwm_mode;
    drv8303_ocp_mode_e      ocp_mode;
    drv8303_oc_adj_set_e    oc_adj_set;
    drv8303_octw_mode_e     octw_mode;
    drv8303_gain_e          gain;
    drv8303_oc_toff_e       oc_toff;

    /**
     * @brief  载入DRV8303配置函数,对结构体变量依次赋值后需要调用该函数,将配置数据写入DRV8303硬件
     * @param  
     * @retval 
     */
    void (*LoadConfig)(void);


    /**
     * @brief  寄存器读取函数,可以读取DRV8303四个寄存器的值
     * @param  regData  读取到的寄存器值
     * @retval 
     */
    void (*ReadStatusRegister)(DRV8303_8BitsType *regData);

} drv8303_t;

void DRV830X_LoadConfig(void);
extern drv8303_t drv8303[DRV8303_NUM];

#endif
#include "drv8303.h"
#include "pid.h"
#include "delay.h"

#define DRV8303_CONFIG  GATE_DRIVE_PEAK_CURRENT_1A7, PWM6_INPUTS_MODE, CURRENT_LIMIT, OC_0V138, REPORT_OT_AND_nOCTW, GAIN_10, CYCLE_BY_CYCLE

DRV8303_8BitsType configResponse[4];
void DRV830X_LoadConfig(void);
void ReadStatusRegister(DRV8303_8BitsType *regData);
drv8303_t drv8303[DRV8303_NUM] = { {DRV8303_CONFIG, DRV830X_LoadConfig, ReadStatusRegister} };
void ConfigToCommand(DRV8303_8BitsType drv8303Index,DRV8303_8BitsType* command)
{
 
    /* 配置变量 */
    DRV8303_16BitsType config[4];
    /* 配置格式化 */
    config[0] = ( (drv8303[drv8303Index].oc_adj_set << 6) + (drv8303[drv8303Index].ocp_mode << 4) + (drv8303[drv8303Index].pwm_mode << 3) + (drv8303[drv8303Index].gate_current) & 0x07FB);
    config[1] = ( (drv8303[drv8303Index].oc_toff << 6) + (drv8303[drv8303Index].gain << 2) + (drv8303[drv8303Index].octw_mode) & 0x004F);

    /* 设置DRV8303的控制寄存器1 */
    command[0] = (0x00 << 7) + (0x02 << 3) + ((config[0] & 0x0700) >> 8);
    command[1] = config[0] & 0x00FF;
    /* 设置DRV8303的控制寄存器2 */
    command[2] = (0x00 << 7) + (0x03 << 3) + ((config[1] & 0x0700) >> 8);
    command[3] = config[1] & 0x00FF;
}

void DRV830X_LoadConfig(void)
{
    /* 配置变量与命令变量 */
    DRV8303_8BitsType wControlCommand[4]={0,0,0,0};
	DRV8303_8BitsType rControlCommand[4]={0,0,0,0};
    DRV8303_8BitsType controlResponse[4]={0,0,0,0};
	while(1)
	{
		/* 配置字 转 通信指令 */
		ConfigToCommand(0,wControlCommand);
		rControlCommand[0] = 0x80 | ((0x02 & 0x03) << 3);
        rControlCommand[1] = 0x00;
	    rControlCommand[2] = 0x80 | ((0x03 & 0x03) << 3);
        rControlCommand[3] = 0x00;
		/* 设置DRV8303的控制寄存器1 */
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_Transmit(&hspi3,wControlCommand, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		/* 设置DRV8303的控制寄存器2 */
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_Transmit(&hspi3,wControlCommand+2, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		/* 读取DRV8303的控制寄存器1 */
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_TransmitReceive(&hspi3,rControlCommand,controlResponse, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_TransmitReceive(&hspi3,rControlCommand,controlResponse, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		/* 读取DRV8303的控制寄存器2 */
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_TransmitReceive(&hspi3,rControlCommand+2,controlResponse+2, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		DRV8303_CS();
		delay_us(1);
		HAL_SPI_TransmitReceive(&hspi3,rControlCommand+2,controlResponse+2, 2, 1000);
		DRV8303_NCS();
		delay_us(1);
		if(	controlResponse[0]==wControlCommand[0]&&controlResponse[1]==wControlCommand[1]&&controlResponse[2]==wControlCommand[2]&&controlResponse[3]==wControlCommand[3])
		{
			break;
		}
		else
		{
			wControlCommand[0] = 0;
			wControlCommand[1] = 0;
			wControlCommand[2] = 0;
			wControlCommand[3] = 0;
		}
	}
}

drv8303配置函数ConfigToCommand(0,wControlCommand);执行后wControlCommand[4]={0x11 0xC0 0x18 0x00}。而drv8303的spi配置要求写入控制寄存器的最高位必须是0,读取控制、状态寄存器最高位必须是1。

spi配置代码如下:

void MX_SPI3_Init(void)
{

  /* SPI3 parameter configuration*/
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi3.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

  hspi3.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;

刚开始将spi配置为16位传输方式,但是drv8303的配置数组wControlCommand是以字节定义的。调用HAL_SPI_Transmit(&hspi3,wControlCommand, 2, 1000);误认为发送16位需要发送两个字节导致sdo返回数据一直错误。实际库函数HAL_SPI_Transmit或HAL_SPI_TransmitReceive里面发送的字节数与配置语句hspi3.Init.DataSize = SPI_DATASIZE_16BIT有关,如果是16位发送两次实际是发送32位4字节。且stm32是小端模式hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;配置要求高字节在前,所以用示波器抓数据会发现stm32的mosi口发出的数据0xC0 0x11 0x00  0x18,并非是希望的0x11 0xC0 0x18 0x00。读取指令rControlCommand[4]={0x90 0x00 0x98 0x00}高低字节颠倒则会发出0x00 0x90 0x00 0x98而读取指令最高位要求为1所以数据一直出错。

改正的办法是将 hspi3.Init.DataSize = SPI_DATASIZE_16BIT;改为hspi3.Init.DataSize = SPI_DATASIZE_8BIT;

dr8303配置调用库函数如下:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tickstart = 0U;
  HAL_StatusTypeDef errorcode = HAL_OK;

  /* Check Direction parameter */
  assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));

  /* Process Locked */
  __HAL_LOCK(hspi);

  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();

  if(hspi->State != HAL_SPI_STATE_READY)
  {
    errorcode = HAL_BUSY;
    goto error;
  }

  if((pData == NULL ) || (Size == 0))
  {
    errorcode = HAL_ERROR;
    goto error;
  }

  /* Set the transaction information */
  hspi->State       = HAL_SPI_STATE_BUSY_TX;
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pTxBuffPtr  = (uint8_t *)pData;
  hspi->TxXferSize  = Size;
  hspi->TxXferCount = Size;

  /*Init field not used in handle to zero */
  hspi->pRxBuffPtr  = (uint8_t *)NULL;
  hspi->RxXferSize  = 0U;
  hspi->RxXferCount = 0U;
  hspi->TxISR       = NULL;
  hspi->RxISR       = NULL;

  /* Configure communication direction : 1Line */
  if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
  {
    SPI_1LINE_TX(hspi);
  }

#if (USE_SPI_CRC != 0U)
  /* Reset CRC Calculation */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SPI_RESET_CRC(hspi);
  }
#endif /* USE_SPI_CRC */

  /* Check if the SPI is already enabled */
  if((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }

  /* Transmit data in 16 Bit mode */
  if(hspi->Init.DataSize == SPI_DATASIZE_16BIT)
  {
    if((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01))
    {
      hspi->Instance->DR = *((uint16_t *)pData);
      pData += sizeof(uint16_t);
      hspi->TxXferCount--;
    }
    /* Transmit data in 16 Bit mode */
    while (hspi->TxXferCount > 0U)
    {
      /* Wait until TXE flag is set to send data */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
      {
          hspi->Instance->DR = *((uint16_t *)pData);
          pData += sizeof(uint16_t);
          hspi->TxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
  /* Transmit data in 8 Bit mode */
  else
  {
    if((hspi->Init.Mode == SPI_MODE_SLAVE)|| (hspi->TxXferCount == 0x01))
    {
      *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);
      pData += sizeof(uint8_t);
      hspi->TxXferCount--;
    }
    while (hspi->TxXferCount > 0U)
    {
      /* Wait until TXE flag is set to send data */
      if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
      {
        *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);
        pData += sizeof(uint8_t);
        hspi->TxXferCount--;
      }
      else
      {
        /* Timeout management */
        if((Timeout == 0U) || ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout)))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }

  /* Wait until TXE flag */
  if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_TXE, SET, Timeout, tickstart) != HAL_OK)
  {
    errorcode = HAL_TIMEOUT;
    goto error;
  }
  
  /* Check Busy flag */
  if(SPI_CheckFlag_BSY(hspi, Timeout, tickstart) != HAL_OK)
  {
    errorcode = HAL_ERROR;
    hspi->ErrorCode = HAL_SPI_ERROR_FLAG;
    goto error;
  }

  /* Clear overrun flag in 2 Lines communication mode because received is not read */
  if(hspi->Init.Direction == SPI_DIRECTION_2LINES)
  {
    __HAL_SPI_CLEAR_OVRFLAG(hspi);
  }
#if (USE_SPI_CRC != 0U)
  /* Enable CRC Transmission */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
     SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
  }
#endif /* USE_SPI_CRC */

  if(hspi->ErrorCode != HAL_SPI_ERROR_NONE)
  {
    errorcode = HAL_ERROR;
  }

error:
  hspi->State = HAL_SPI_STATE_READY;
  /* Process Unlocked */
  __HAL_UNLOCK(hspi);
  return errorcode;
}
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tmp = 0U, tmp1 = 0U;
#if (USE_SPI_CRC != 0U)
  __IO uint16_t tmpreg1 = 0U;
#endif /* USE_SPI_CRC */
  uint32_t tickstart = 0U;
  /* Variable used to alternate Rx and Tx during transfer */
  uint32_t txallowed = 1U;
  HAL_StatusTypeDef errorcode = HAL_OK;

  /* Check Direction parameter */
  assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction));

  /* Process Locked */
  __HAL_LOCK(hspi);

  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();
  
  tmp  = hspi->State;
  tmp1 = hspi->Init.Mode;
  
  if(!((tmp == HAL_SPI_STATE_READY) || \
    ((tmp1 == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp == HAL_SPI_STATE_BUSY_RX))))
  {
    errorcode = HAL_BUSY;
    goto error;
  }

  if((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
  {
    errorcode = HAL_ERROR;
    goto error;
  }

  /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */
  if(hspi->State == HAL_SPI_STATE_READY)
  {
    hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
  }

  /* Set the transaction information */
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pRxBuffPtr  = (uint8_t *)pRxData;
  hspi->RxXferCount = Size;
  hspi->RxXferSize  = Size;
  hspi->pTxBuffPtr  = (uint8_t *)pTxData;
  hspi->TxXferCount = Size;
  hspi->TxXferSize  = Size;

  /*Init field not used in handle to zero */
  hspi->RxISR       = NULL;
  hspi->TxISR       = NULL;

#if (USE_SPI_CRC != 0U)
  /* Reset CRC Calculation */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SPI_RESET_CRC(hspi);
  }
#endif /* USE_SPI_CRC */

  /* Check if the SPI is already enabled */
  if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }

  /* Transmit and Receive data in 16 Bit mode */
  if(hspi->Init.DataSize == SPI_DATASIZE_16BIT)
  {
    if((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U))
    {
      hspi->Instance->DR = *((uint16_t *)pTxData);
      pTxData += sizeof(uint16_t);
      hspi->TxXferCount--;
    }
    while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
    {
      /* Check TXE flag */
      if(txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
      {
        hspi->Instance->DR = *((uint16_t *)pTxData);
        pTxData += sizeof(uint16_t);
        hspi->TxXferCount--;
        /* Next Data is a reception (Rx). Tx not allowed */ 
        txallowed = 0U;

#if (USE_SPI_CRC != 0U)
        /* Enable CRC Transmission */
        if((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE))
        {
          SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
        }
#endif /* USE_SPI_CRC */
      }

      /* Check RXNE flag */
      if((hspi->RxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)))
      {
        *((uint16_t *)pRxData) = hspi->Instance->DR;
        pRxData += sizeof(uint16_t);
        hspi->RxXferCount--;
        /* Next Data is a Transmission (Tx). Tx is allowed */ 
        txallowed = 1U;
      }
      if((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
    }
  }
  /* Transmit and Receive data in 8 Bit mode */
  else
  {
    if((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U))
    {
      *((__IO uint8_t*)&hspi->Instance->DR) = (*pTxData);
      pTxData += sizeof(uint8_t);
      hspi->TxXferCount--;
    }
    while((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
    {
      /* check TXE flag */
      if(txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
      {
        *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++);
        hspi->TxXferCount--;
        /* Next Data is a reception (Rx). Tx not allowed */ 
        txallowed = 0U;

#if (USE_SPI_CRC != 0U)
        /* Enable CRC Transmission */
        if((hspi->TxXferCount == 0U) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE))
        {
          SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
        }
#endif /* USE_SPI_CRC */
      }

      /* Wait until RXNE flag is reset */
      if((hspi->RxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)))
      {
        (*(uint8_t *)pRxData++) = hspi->Instance->DR;
        hspi->RxXferCount--;
        /* Next Data is a Transmission (Tx). Tx is allowed */ 
        txallowed = 1U;
      }
      if((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick()-tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
    }
  }

#if (USE_SPI_CRC != 0U)
  /* Read CRC from DR to close CRC calculation process */
  if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    /* Wait until TXE flag */
    if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SET, Timeout, tickstart) != HAL_OK)
    {
      /* Error on the CRC reception */
      SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
      errorcode = HAL_TIMEOUT;
      goto error;
    }
    /* Read CRC */
    tmpreg1 = hspi->Instance->DR;
    /* To avoid GCC warning */
    UNUSED(tmpreg1);
  }

  /* Check if CRC error occurred */
  if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_CRCERR))
  {
    SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_CRC);
    /* Clear CRC Flag */
    __HAL_SPI_CLEAR_CRCERRFLAG(hspi);

    errorcode = HAL_ERROR;
  }
#endif /* USE_SPI_CRC */

  /* Wait until TXE flag */
  if(SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_TXE, SET, Timeout, tickstart) != HAL_OK)
  {
    errorcode = HAL_TIMEOUT;
    goto error;
  }
  
  /* Check Busy flag */
  if(SPI_CheckFlag_BSY(hspi, Timeout, tickstart) != HAL_OK)
  {
    errorcode = HAL_ERROR;
    hspi->ErrorCode = HAL_SPI_ERROR_FLAG;
    goto error;
  }

  /* Clear overrun flag in 2 Lines communication mode because received is not read */
  if(hspi->Init.Direction == SPI_DIRECTION_2LINES)
  {
    __HAL_SPI_CLEAR_OVRFLAG(hspi);
  }
  
error :
  hspi->State = HAL_SPI_STATE_READY;
  __HAL_UNLOCK(hspi);
  return errorcode;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值