SPI-Loopback mit DMA

Ich verwende das STM32F4 Discovery Board und versuche, SPI-Loopback mit DMA zu erhalten.

Ich habe erfolgreich ein "Nur-SPI"-Loopback zum Laufen gebracht, aber jetzt möchte ich zusätzlich DMA mit dem SPI verwenden. Hier sind die Funktionen, die ich verwende:

Initialisierung von SPI

void init_SPI1(void){    
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStruct;
  SPI_InitTypeDef SPI_InitStruct ;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  // connect SPI1 pins to SPI alternate function

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

  //Set chip select high 
  GPIOA->BSRRL |= GPIO_Pin_4; // set PA4 high

  // enable SPI1 peripheral clock
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  /* configure SPI1 in Mode 0 
   * CPOL = 0 --> clock is low when idle
   * CPHA = 0 --> data is sampled at the first edge*/
  SPI_StructInit(&SPI_InitStruct); // set default settings 
  SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
  SPI_InitStruct.SPI_Mode = SPI_Mode_Master;     // transmit in master mode, NSS pin has to be always high
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;        // clock is low when idle
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;      // data sampled at first edge
  SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
  SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
  SPI_Init(SPI1, &SPI_InitStruct); 

  NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  

  return;
}        

Konfiguration von DMA:

void DMA_Config()
{  
DMA_InitTypeDef DMA_InitStructure;   
NVIC_InitTypeDef NVIC_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

DMA_ClearFlag(DMA2_Stream2,        DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
DMA_Cmd(DMA2_Stream2, DISABLE);
while (DMA2_Stream2->CR & DMA_SxCR_EN);
DMA_DeInit(DMA2_Stream5);
DMA_StructInit(&DMA_InitStructure);

DMA_InitStructure.DMA_Channel = DMA_Channel_3;
DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t) &(SPI1->DR);
DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t) &spiTxBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize  = SPI_TX_MAX;
DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority  = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;

DMA_Init(DMA2_Stream5, &DMA_InitStructure); 

/**
configuration of the interrupts of DMA
******************************************************/
DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);  
return;
}

SPI-Schreibfunktion:

void SPI1_Write(uint8_t *txBuff,int length,tSPI_Callback fct)
{
 DMA2_Stream5->M0AR = (uint32_t) &spiTxBuff;
 DMA_Cmd(DMA2_Stream5, ENABLE);
 SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
 SPI_Cmd(SPI1, ENABLE);
}

Die empfangenen Daten werden mit dem SPI-Interrupt-Handler in den Rx Buffer geschrieben.

void SPI1_IRQHandler()
{
 spiRxBuff[spiRxCount] = SPI_I2S_ReceiveData(SPI1);
 spiRxCount++;
}

Ich rufe diese Funktionen main()wie folgt auf:

Haupt c:

DMA_Config();
init_SPI1();
SPI1_Write(spiTxBuff,SPI_TX_MAX,(void*)0); 

Mit einem Debugger habe ich festgestellt, dass im DMA-High-Interrupt-Statusregister TCIF5 (Transfer Complete Flag) und HTIF5 (Half Transfer Complete Flag) auf 1 gesetzt sind, was bedeutet, dass die Übertragung meiner Meinung nach erfolgreich durchgeführt wurde, aber ich habe es getan bekomme keine Daten im SPI Rx Buffer. Die zweite seltsame Sache ist, dass weder DMA-Interrupt noch SPI-Interrupt ausgelöst werden. Können Sie mir bitte helfen, herauszufinden, was in meinem Code falsch ist?

Was ist mit dem Tx, funktioniert es? Haben Sie versucht, einen Haltepunkt in den SPI-Interrupt-Handler zu setzen, um zu überprüfen, ob er jemals ausgelöst wird?

Antworten (1)

Es gibt einige Fehler, die ich korrigiert habe und das erwartete Ergebnis erhalten:

1) SPI Rx-Interrupt ist nicht konfiguriert, diese Zeile SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE)wurde übersehen

2) In der Funktion DMA_Config werden DMA1-Interrupts statt DMA2 dieser Leitung aktiviertNVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;

Dies ist die funktionierende Lösung