STM32 SPI Передача DMA при внешнем прерывании - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть чип АЦП, подключенный через SPI к STM32H7x MCU.MCU является ведущим устройством, но АЦП посылает сигнал «Готовность данных» всякий раз, когда новые значения готовы к передаче.Моя старая реализация (которая работает) слушает внешнее прерывание (Data ready) и вызывает передачу SPI (драйвер KEIL) для считывания значений.Он передает фиксированные 32 байта и считывает синхронизацию 32 байта.До сих пор все работает нормально.

Проблема в том, что когда я увеличиваю частоту дискретизации выше 20 000 выборок в секунду, она работает слишком медленно, и процессор слишком часто прерывается, и я больше ничего не могу сделать.Моя цель - увеличить частоту дискретизации до 32K в секунду.Драйвер spil Keil использует DMA под уровнем, но все еще прерывает процессор 32K раз в секунду - это слишком много.

Я думаю, что должен быть способ настроить низкоуровневую DMA, чтобы начать передачу, когда происходит внешнее событие (сигнал готовности данных).Моя цель - настроить DMA таким образом, чтобы считывать значения для каждого сигнала DRDY несколько раз (например, 128 раз и записывать его в буфер), а затем давать мне прерывание.Таким образом, мне нужно иметь дело только с 32000/128 = 250 раз в секунду, что вполне разумно.

Я использую CubeMX для создания низкоуровневого драйвера SPI DMA, пока у меня есть что-то вроде этого:

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)


{

  GPIO_InitTypeDef GPIO_InitStruct;
  HAL_DMA_MuxSyncConfigTypeDef pSyncConfig;
  if(hspi->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();


/**SPI2 GPIO Configuration    
PB4     ------> SPI2_NSS
PA12    ------> SPI2_SCK
PC2     ------> SPI2_MISO
PC3     ------> SPI2_MOSI 
*/
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

/* SPI2 DMA Init */
/* SPI2_TX Init */
hdma_spi2_tx.Instance = DMA1_Stream0;
hdma_spi2_tx.Init.Request = DMA_REQUEST_SPI2_TX;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_DISABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_spi2_tx.Init.Mode = DMA_NORMAL;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_EXTI0;
pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_RISING_FALLING;
pSyncConfig.SyncEnable = ENABLE;
pSyncConfig.EventEnable = DISABLE;
pSyncConfig.RequestNumber = 1;
if (HAL_DMAEx_ConfigMuxSync(&hdma_spi2_tx, &pSyncConfig) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

__HAL_LINKDMA(hspi,hdmatx,hdma_spi2_tx);

/* SPI2_RX Init */
hdma_spi2_rx.Instance = DMA1_Stream1;
hdma_spi2_rx.Init.Request = DMA_REQUEST_SPI2_RX;
hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_spi2_rx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_DMAMUX1_CH0_EVT;
pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_NO_EVENT;
pSyncConfig.SyncEnable = DISABLE;
pSyncConfig.EventEnable = ENABLE;
pSyncConfig.RequestNumber = 1;
if (HAL_DMAEx_ConfigMuxSync(&hdma_spi2_rx, &pSyncConfig) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

__HAL_LINKDMA(hspi,hdmarx,hdma_spi2_rx);

/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);


/* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }

}

Инициализация SPI и DMA происходит следующим образом:

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

  /* DMA interrupt init */
  /* DMA1_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  /* DMA1_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
  /* DMAMUX1_OVR_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMAMUX1_OVR_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMAMUX1_OVR_IRQn);

}

/* SPI2 init function */
static void MX_SPI2_Init(void)
{

  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_32BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;

  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

Внешние данные готовы подключены к PB0 GPIO.С этого момента я понятия не имею, как сказать DMA прослушивать внешнее событие и как установить адреса буфера TX / RX, а также как сказать DMA, что у меня есть буфер RX, способный на 128 блоков чтения, и как настроить DMA для создания прерываниякогда буфер RX заполнен.

Весь смысл в том, чтобы не использовать функцию HAL_SPI_Transmit_DMA.Потому что это требует, чтобы я обрабатывал внешнее прерывание DRDY вручную, и я получу то же решение, которое у меня уже есть.

Ответы [ 2 ]

0 голосов
/ 12 августа 2019

Для H7 myabe вы должны открыть прерывание, очистка PR инициирует синхронизацию. Это очень маленькая особенность. Прерывания не сохранены, только операции SPI сохранены (с использованием DMA)

0 голосов
/ 19 сентября 2018

Я точно не знаю реализацию DMA STM32H7.

На других контроллерах STM32 вы можете выбрать прерывание триггера DMA, например, переполнение таймера.Проблема в том, что после запуска триггера ваша первая передача DMA должна быть заменена на пустой триггер буфера SPI RX, который не может быть выполнен автоматически.

Также вы должны проверить, может ли прерывание EXT Pin использоваться кактриггер DMA.

Модуль D7 H7 намного более продвинут, чем контроллеры DMA, с которыми я обычно работаю, поэтому может быть возможность решить упомянутые задачи.

...