STM32 SPI Получение DMA получает данные мусора

В моем проекте я использую связь Master SPI для получения аналоговых данных от внешнего АЦП. Мой MCU - STM32F746ZGTX. Моя система должна работать в режиме реального времени, поэтому я использовал функции приема и передачи SPI DMA.

Я правильно читаю все данные внешнего АЦП с опросом SPI без использования DMA. При опросе SPI я сначала отправляю управляющий байт на внешний АЦП, в это время программа ожидает while(SPI_Ready) цикл, а затем начинает получать все данные АЦП. Этот сценарий работает отлично.

Но я не хочу ждать в while(SPI_Ready) цикл в каждом моем чтении АЦП. Потому что это влияет на мои расчеты в реальном времени. Вот почему я переключил свои функции на DMA.

Мой новый алгоритм таков ниже:

  1. Генерация внешнего прерывания GPIO с помощью спадающего фронта, чтобы определить готовность данных к выводу внешнего АЦП.
  2. Сделайте вывод выбора чипа низким, чтобы начать связь с внешним АЦП
  3. Отправить команду чтения на внешний АЦП с HAL_SPI_Transmit_DMA() функция.
  4. В HAL_SPI_TxCpltCallback функция, триггер HAL_SPI_Receive_DMA()
  5. В HAL_SPI_RxCpltCallback Функция, буферизует принятые данные АЦП и заставляет микросхему выбирать высокий вывод для прекращения связи

Когда я использую этот алгоритм, я всегда получаю значения 0xFF в моем буфере АЦП. Похоже, даже если АЦП не отправляет необработанные данные, из-за запуска приема DMA My MCU отправляет тактовый сигнал и воспринимает весь логический сигнал высокого уровня как полученные данные.

Я делюсь своими кодами ниже. Если у вас есть предложения, где я ошибаюсь, пожалуйста, поделитесь своим мнением.

 /* SPI1 init function */
 static void MX_SPI1_Init(void)
 {

   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_HIGH;
   hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
   hspi1.Init.NSS = SPI_NSS_SOFT;
   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
   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)
   {

   }
  }

  void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
  {

     GPIO_InitTypeDef GPIO_InitStruct;
     if(hspi->Instance==SPI1)
     {
        /* USER CODE BEGIN SPI1_MspInit 0 */

        /* USER CODE END SPI1_MspInit 0 */
        /* Peripheral clock enable */
        __HAL_RCC_SPI1_CLK_ENABLE();

        /**SPI1 GPIO Configuration    
        PA5     ------> SPI1_SCK
        PA6     ------> SPI1_MISO
        PB5     ------> SPI1_MOSI 
        */
        GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
        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);

        GPIO_InitStruct.Pin = GPIO_PIN_5;
        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(GPIOB, &GPIO_InitStruct);

        /* SPI1 DMA Init */
        /* SPI1_RX Init */
        hdma_spi1_rx.Instance = DMA2_Stream0;
        hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
        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;
        hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
        {

        }

        __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);

        /* SPI1_TX Init */
        hdma_spi1_tx.Instance = DMA2_Stream3;
        hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
        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;
        hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
        {

        }

         __HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);

        /* SPI1 interrupt Init */
        HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(SPI1_IRQn);
        /* USER CODE BEGIN SPI1_MspInit 1 */

        /* USER CODE END SPI1_MspInit 1 */

        /* USER CODE BEGIN SPI1_MspInit 1 */

        /* USER CODE END SPI1_MspInit 1 */
        }

        }

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{

  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
  /* Peripheral clock disable */
  __HAL_RCC_SPI1_CLK_DISABLE();

  /**SPI1 GPIO Configuration    
   PA5     ------> SPI1_SCK
   PA6     ------> SPI1_MISO
   PB5     ------> SPI1_MOSI 
  */
  HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6);

  HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5);

  /* USER CODE BEGIN SPI1_MspDeInit 1 */
  /* Peripheral DMA DeInit*/
  HAL_DMA_DeInit(hspi->hdmarx);
  HAL_DMA_DeInit(hspi->hdmatx);

  /* Peripheral interrupt Deinit*/
  HAL_NVIC_DisableIRQ(SPI2_IRQn);
 /* USER CODE END SPI1_MspDeInit 1 */
 }
}

/* External Interrupt for data ready output of ADC */
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  adc_selectADC(); /* Make Chip Select pin low */
  HAL_SPI_Transmit_DMA (&hspi1, &controlByte, 1);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
   if (hspi->Instance == hspi1.Instance)
   {
       /* Transmit is completed */
       /* Trigger receive DMA to get raw data from external ADC */
       HAL_SPI_Receive_DMA (&hspi1, (uint8_t*)adcRecBuffer, 24);
   }
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
   if (hspi->Instance == hspi1.Instance)
   {
       /* Receive is completed */
       adc_deselectADC(); /* Make Chip Select pin high */
   }         
}

***Working Algorithm without using DMA or Interrupt:***

/* External Interrupt for data ready output of ADC */
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  adc_selectADC(); /* Make Chip Select pin low */

  while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
  HAL_SPI_Transmit(&hspi1, &controlByte, 1,1);
  while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);

  while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
  HAL_SPI_Receive(&hspi1, (uint8_t*)adcRecBuffer, 24, 1);
  while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);

  adc_deselectADC(); /* Make Chip Select pin high*/

}

0 ответов

SPI обычно является полнодуплексным, что означает, что "чтение" на самом деле является генератором тактовых импульсов и передачей нулей. В реализации STM HAL функция "приема" просто отправляет данные, которые у вас есть в буфере чтения. Могут быть нули, может быть мусор, который ваш АЦП интерпретирует как некоторые команды и переходит в некое плохое состояние.

Попробуйте выполнить TransmitReceive из 2 25-байтовых буферов с первым идентификатором команды ("управляющий байт"), а затем 24 нулевыми байтами в буфере TX. В ответ вы должны получить буфер RX размером 25, из которого можно отбросить первый байт. Таким образом, вам нужно обрабатывать только прерывание RXCplt, когда вы отпускаете вывод ADC CS.

Другие вопросы по тегам