Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
foxis
Родился
Сообщения: 4
Зарегистрирован: Сб ноя 28, 2015 21:08:45

Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение foxis »

Здравствуйте,
в процессе обучения программированию SPI на плате Nucleo-L053R8
возникли проблемы с передачей байта.

В данной статье описывается
один из простейших способов передачи, когда в один и тот же модуль
spi сначала передается байт данных, а потом принимается данный байт.

Для этого нужно кинуть перемычку между MISO и MOSI в SPI1 (в моей плате соединяются PA6, PA7).

Перемычку кинул, инициализацию провел в Cube.
Передаю и принимаю байт с помощью:

Код: Выделить всё

  HAL_SPI_Transmit(&hspi1, transmitBuffer, 1, 20);
  HAL_SPI_Receive_IT(&hspi1, receiveBuffer, 1);
соответственно.

Однако когда программа доходит до while(1)
в переменной receiveBuffer - пусто. А должен быть символ "v".

В чем может быть проблема ?
Спойлер

Код: Выделить всё


  */
/* Includes ------------------------------------------------------------------*/
#include "stm32l0xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t transmitBuffer[1] = "v"; 
uint8_t receiveBuffer[1];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

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

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();

  /* USER CODE BEGIN 2 */

  HAL_SPI_Transmit(&hspi1, transmitBuffer, 1, 20);
  HAL_SPI_Receive_IT(&hspi1, receiveBuffer, 1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI1 init function */
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_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
  hspi1.Init.CRCPolynomial = 7;
  HAL_SPI_Init(&hspi1);

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
     PA2   ------> USART2_TX
     PA3   ------> USART2_RX
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOC_CLK_ENABLE();
  __GPIOH_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : USART_TX_Pin USART_RX_Pin */
  GPIO_InitStruct.Pin = USART_TX_Pin|USART_RX_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : LD2_Pin */
  GPIO_InitStruct.Pin = LD2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif



Реклама
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение Аlex »

foxis писал(а):В чем может быть проблема ?
Да в чём угодно. Начиная от неправильно сконфигурированного модуля и его использования, заканчивая "железными" проблемами. У Вас железо в руках, пройдите отладкой.
Ну а вообще, для справки, SPI передаёт и принимает данные одновременно. Т.е. приём битов на MOSI идёт одновременно с передачей битов по MISO.
Реклама
foxis
Родился
Сообщения: 4
Зарегистрирован: Сб ноя 28, 2015 21:08:45

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение foxis »

Аlex писал(а):
foxis писал(а):В чем может быть проблема ?
Да в чём угодно. Начиная от неправильно сконфигурированного модуля и его использования, заканчивая "железными" проблемами. У Вас железо в руках, пройдите отладкой.
Ну а вообще, для справки, SPI передаёт и принимает данные одновременно. Т.е. приём битов на MOSI идёт одновременно с передачей битов по MISO.
Импульсы определенные появляются при прохождении строки (в режиме отладки):

Код: Выделить всё

HAL_SPI_Transmit(&hspi1, transmitBuffer, 1, 20);


Также после этой же строки значение из transmitBuffer переносится в регистр DR.

После строки

Код: Выделить всё

HAL_SPI_Receive_IT(&hspi1, receiveBuffer, 1);
Регистр DR очищается, но receiveBuffer остается пустым.



Насчет синхронного приема и передачи я в курсе, но как это может помочь найти ошибку ?
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение Аlex »

foxis писал(а): После строки

Код: Выделить всё

HAL_SPI_Receive_IT(&hspi1, receiveBuffer, 1);
Регистр DR очищается, но receiveBuffer остается пустым.
А зайти в эту строку функцию и пошагать там ?

Попробуйте разорвать связь. Будет ли содержаться значение в регистре после передачи ? Для начала хоть узнаете, реально ли данные передаются, или Вы просто видите записанное туда значение.
Реклама
Эиком - электронные компоненты и радиодетали
foxis
Родился
Сообщения: 4
Зарегистрирован: Сб ноя 28, 2015 21:08:45

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение foxis »

Аlex писал(а):
foxis писал(а): После строки

Код: Выделить всё

HAL_SPI_Receive_IT(&hspi1, receiveBuffer, 1);
Регистр DR очищается, но receiveBuffer остается пустым.
А зайти в эту строку функцию и пошагать там ?

Попробуйте разорвать связь. Будет ли содержаться значение в регистре после передачи ? Для начала хоть узнаете, реально ли данные передаются, или Вы просто видите записанное туда значение.
Аlex,

1) Код функции HAL_SPI_Receive_IT
Спойлер

Код: Выделить всё

/**
  * @brief  Receive an amount of data in no-blocking mode with Interrupt
  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
  *                the configuration information for SPI module.
  * @param  pData: pointer to data buffer
  * @param  Size: amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
{
  if(hspi->State == HAL_SPI_STATE_READY)
  {
    if((pData == NULL) || (Size == 0)) 
    {
      return  HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(hspi);

    /* Configure communication */
    hspi->State        = HAL_SPI_STATE_BUSY_RX;
    hspi->ErrorCode    = HAL_SPI_ERROR_NONE;

    hspi->RxISR        = &SPI_RxISR;
    hspi->pRxBuffPtr   = pData;
    hspi->RxXferSize   = Size;
    hspi->RxXferCount  = Size ; 

   /*Init field not used in handle to zero */
    hspi->TxISR        = 0;
    hspi->pTxBuffPtr   = NULL;
    hspi->TxXferSize   = 0;
    hspi->TxXferCount  = 0;

    /* Configure communication direction : 1Line */
    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
    {
      SPI_1LINE_RX(hspi);
    }
    else if((hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->Init.Mode == SPI_MODE_MASTER))
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hspi);

      /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
      return HAL_SPI_TransmitReceive_IT(hspi, pData, pData, Size);
    }

    /* Reset CRC Calculation */
    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    {
      SPI_RESET_CRC(hspi);
    }

    /* Enable TXE and ERR interrupt */
    __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_RXNE | SPI_IT_ERR));

    /* Process Unlocked */
    __HAL_UNLOCK(hspi);

    /* Note : The SPI must be enabled after unlocking current process 
              to avoid the risk of SPI interrupt handle execution before current
              process unlock */

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

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}
В ней компилятор заходит в

Код: Выделить всё

 else if((hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->Init.Mode == SPI_MODE_MASTER))
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hspi);

      /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
      return HAL_SPI_TransmitReceive_IT(hspi, pData, pData, Size);
    }
и после строки return HAL_SPI_TransmitReceive_IT(hspi, pData, pData, Size);
обнуляет регистр DR.

2) Если перемычку между РА6 и РА7 убрать, то в регистр DR вообще ничего не заносится
ни во время приема, ни во время передачи (он всегда равен нулю).

Видимо DR все таки заполняется когда идет прием данных.
Реклама
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение Аlex »

foxis писал(а): и после строки return HAL_SPI_TransmitReceive_IT(hspi, pData, pData, Size);
обнуляет регистр DR.
А Вас не смутило название этой строки функции ? :) Тем более, ещё и её аргументы обо всём говорят.
Зайдите в неё отладкой и увидите, что она передаёт данные из одного буфера и принимает в другой. А не просто читает регистр DR.
Вообще, учитывая, что
foxis писал(а):Насчет синхронного приема и передачи я в курсе
, странно, что Вы до сих пор не поняли, почему у Вас ничего не принимается.
Реклама
foxis
Родился
Сообщения: 4
Зарегистрирован: Сб ноя 28, 2015 21:08:45

Re: Простая передача по SPI на плате Nucleo-L053R8 (STM32)

Сообщение foxis »

Аlex писал(а):
А Вас не смутило название этой строки функции ? :) Тем более, ещё и её аргументы обо всём говорят.
Зайдите в неё отладкой и увидите, что она передаёт данные из одного буфера и принимает в другой. А не просто читает регистр DR.
Аlex, да, спасибо, теперь я понимаю, что там имеется сдвиговый регистр, а также TX, RX буферы.
Данные сначала поступают на TX буфер, потом уходят в сдвиговый регистр. Я так понял,
что DR это и есть тот самый сдвиговый регистр.
Аlex писал(а): странно, что Вы до сих пор не поняли, почему у Вас ничего не принимается.
1) Согласен, прием не работает. По крайней мере если с соединенной перемычкой между
РА6, РА7 регистр DR ведется себя по разному, то хотя бы в электрической связи можно не сомневаться,
дело скорее всего в программной реализации.

2) При отладке заметил, что флаг TXE устанавливается, а вот флаг RXNE не хочет устанавливаться.
Ни совсем понятно, что мешает данному флагу установиться ?
Вроде есть перемычка, регистр DR заполнен, что еще не хватает ?
Ответить

Вернуться в «ARM»