SPI主设备触发无法控制的DMA TC中断,却什么也没收到

时间:2019-05-13 09:48:54

标签: stm32 spi dma hal

我已经在mbed论坛上问过this question,但是我没有收到答案。

简介

我有两个Nucleo L432kc板,我想让它们使用DMA与SPI协议通信。

在以下方案中,您可以看到实际的硬件设置: enter image description here

什么有效

如果我将数据从主机发送到从机,则可以正确接收数据,而当主机不发送数据时,从机将无法接收任何数据。

主密码

#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;

unsigned int c = 0;

Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3); 

SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;

void Error_Handler(){
  led.write(1);
  while(1){}
}

static void HAL_GPIO_Init(void){

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi1.Instance==SPI1)
  {    
      __HAL_RCC_GPIOA_CLK_ENABLE();
      /**SPI1 GPIO Configuration    
      PA1     ------> SPI1_SCK
      PA11     ------> SPI1_MISO
      PA12     ------> SPI1_MOSI 
      */
      GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
      HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }

  else
    Error_Handler();
}

static void SPI1_Init(void)
{
  __HAL_RCC_SPI1_CLK_ENABLE();

  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

  /* SPI1 interrupt Init */
  HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(SPI1_IRQn);
}

static void DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* SPI1 DMA Init */
  /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA1_Channel2;
    hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

  __HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

    /* SPI1 DMA Init */
  /* SPI1_TX Init */
  hdma_spi1_tx.Instance = DMA1_Channel3;
  hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
  hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_spi1_tx.Init.Mode = DMA_NORMAL;
  hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
  if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
  {
    Error_Handler();
  }

  __HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);

  /* DMA interrupt init */
  /* DMA1_Channel3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

}

extern "C"{

  void DMA1_Channel3_IRQHandler(void)
  {
    HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
    HAL_DMA_IRQHandler(&hdma_spi1_tx);
  }

  void DMA1_Channel2_IRQHandler(void)
  {
    HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
    HAL_DMA_IRQHandler(&hdma_spi1_rx);
  }

  void SPI1_IRQHandler(void)
  {
    HAL_SPI_IRQHandler(&hspi1);
  }
}

void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){

  for(int i = 0; i < receive_buff_length/2; i++){
    buff[i] = dma_buffer_rx[i];
  }

}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){

  for(int i = receive_buff_length/2; i < receive_buff_length; i++){
    buff[i] = dma_buffer_rx[i];
  }

  printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
  memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}

void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){

  c += 5;
  dma_buffer_tx[0] = c & 0xFF; 
  dma_buffer_tx[1] = (c >> 8) & 0xFF;

}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){

  dma_buffer_tx[2] = (c >> 16) & 0xFF;
  dma_buffer_tx[3] = (c >> 24) & 0xFF;
}

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* SPI INIT */
  SPI1_Init();

  /* GPIO USART2 INIT */
  HAL_GPIO_Init();

  /* DMA INIT */
  DMA_Init();

  c = 1000;
  dma_buffer_rx[0] = c & 0xFF; 
  dma_buffer_rx[1] = (c >> 8) & 0xFF;
  dma_buffer_rx[2] = (c >> 16) & 0xFF;
  dma_buffer_rx[3] = (c >> 24) & 0xFF;


  while(true){
    HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length); 
    wait(0.001);
  }
}

从站代码

#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;

unsigned int c = 0;

Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3); 

SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;

void Error_Handler(){
  led.write(1);
  while(1){}
}

static void HAL_GPIO_Init(void){

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi1.Instance==SPI1)
  {    
      __HAL_RCC_GPIOA_CLK_ENABLE();
      /**SPI1 GPIO Configuration    
      PA1     ------> SPI1_SCK
      PA11     ------> SPI1_MISO
      PA12     ------> SPI1_MOSI 
      */
      GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
      HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }

  else
    Error_Handler();
}

static void SPI1_Init(void)
{
  __HAL_RCC_SPI1_CLK_ENABLE();

  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_SLAVE;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

  /* SPI1 interrupt Init */
  HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(SPI1_IRQn);
}

static void DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* SPI1 DMA Init */
  /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA1_Channel2;
    hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

  __HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

    /* SPI1 DMA Init */
  /* SPI1_TX Init */
  hdma_spi1_tx.Instance = DMA1_Channel3;
  hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
  hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_spi1_tx.Init.Mode = DMA_NORMAL;
  hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
  if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
  {
    Error_Handler();
  }

  __HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);

  /* DMA interrupt init */
  /* DMA1_Channel3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

}

extern "C"{

  void DMA1_Channel3_IRQHandler(void)
  {
    HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
    HAL_DMA_IRQHandler(&hdma_spi1_tx);
  }

  void DMA1_Channel2_IRQHandler(void)
  {
    HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
    HAL_DMA_IRQHandler(&hdma_spi1_rx);
  }

  void SPI1_IRQHandler(void)
  {
    HAL_SPI_IRQHandler(&hspi1);
  }
}

void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){

  for(int i = 0; i < receive_buff_length/2; i++){
    buff[i] = dma_buffer_rx[i];
  }

}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){

  for(int i = receive_buff_length/2; i < receive_buff_length; i++){
    buff[i] = dma_buffer_rx[i];
  }

  printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
  memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}

void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){

  c += 5;
  dma_buffer_tx[0] = c & 0xFF; 
  dma_buffer_tx[1] = (c >> 8) & 0xFF;

}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){

  dma_buffer_tx[2] = (c >> 16) & 0xFF;
  dma_buffer_tx[3] = (c >> 24) & 0xFF;
}

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* SPI INIT */
  SPI1_Init();

  /* GPIO USART2 INIT */
  HAL_GPIO_Init();

  /* DMA INIT */
  DMA_Init();

  c = 1000;
  dma_buffer_rx[0] = c & 0xFF; 
  dma_buffer_rx[1] = (c >> 8) & 0xFF;
  dma_buffer_rx[2] = (c >> 16) & 0xFF;
  dma_buffer_rx[3] = (c >> 24) & 0xFF;


  while(true){
    HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length); 
  }
}

什么不起作用

如果我更改了通讯中的角色,那么我将数据从从服务器发送到主服务器,交换以下几行

[...]
HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length); 
wait(0.001);
[...]

具有:

[...]
HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length); 
[...]

即使从站未加电,主站也继续接收中断并调用HAL_SPI_RxCpltCallback。如果我们为从属设备加电,则主设备将打印随机数。

我已经尝试过但没有成功的东西

  1. 我已经在Nucleo F446板上测试了主代码。
  2. 我已经在MISO引脚上设置了下拉电阻和上拉电阻。
  3. 我为硬件连接尝试了不同的电缆。
  4. 我尝试直接使用HAL_SPI_TransmitReceive_DMA函数,但是行为是相同的。

注意事项

HAL_SPI_Receive_DMA来源中走过,我注意到在SPI_MODE_MASTER中实际上调用了HAL_SPI_TransmitReceive_DMA函数。 我认为同一缓冲区用于发送和接收,但是我不知道如何证明这一点。 我还打印了hdma_spi1_rx.Instance->CNDTR,我注意到该值增加到4次抽动实际上是我们将要接收的字节数。

1 个答案:

答案 0 :(得分:0)

SPI主设备始终在发送数据时接收数据。 SPI就是这样工作的。即使SPI不在传输,主机也始终读取数据。