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?
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
Florent