2016-02-15 228 views
1

我使用的是STM32F4發現板,我試圖用DMA獲得SPI回送。 我已經成功地得到一個「SPI-只」環回跑,但現在我想除了與SPI使用DMA,這裏的功能正在使用:帶DMA的SPI回送

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); 

    SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE); 
    return; 
}   

DMA的配置[編輯]:

void DMA_Config() 
{ 
DMA_InitTypeDef DMA_InitStructure; 
NVIC_InitTypeDef NVIC_InitStructure; 

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 

DMA_ClearFlag(DMA2_Stream5,  DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2); 
DMA_Cmd(DMA2_Stream5, DISABLE); 
while (DMA2_Stream5->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 = DMA2_Stream5_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
return; 
} 

SPI寫功能:

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); 
} 

使用spi中斷處理程序將接收到的數據寫入Rx緩衝區。

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

我打電話主這些功能如下:

的main.c:

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

使用調試器,我發現,在高DMA中斷狀態寄存器,TCIF5(轉讓完成標誌)和HTIF5(半傳輸完成標誌)設置爲1意味着傳輸成功完成,但我沒有在SPI Rx緩衝區中獲得任何數據,第二個奇怪的是DMA中斷和SPI中斷被觸發。你能幫我弄清楚我的代碼有什麼問題。

編輯

的DMA和SPI中斷觸發,但問題是現在我得到的是我不能接受的所有元素,我可以收到第一個

uint8_t spiTxBuff[SPI_TX_MAX] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10}; 

spiRxBuff[SPI_RX_MAX] ={0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}

這個問題是由於DMA比中斷處理程序更快,所以SPI中斷處理程序沒有時間來處理所有接收到的數據?

+0

在代碼中有一個對DMA1的引用。應該是「DMA2」嗎? – kkrambo

+0

是的,你是對的謝謝 – fedi

回答

1
  • 正如kkrambo指出的那樣,您正在爲DMA1而不是DMA2啓用中斷。不要忘記在那裏安裝中斷處理程序。
  • 什麼是DMA2_Stream2的東西?
  • SPI中斷顯然沒有配置(或者我找不到)。像: SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);
+0

謝謝@berendi,現在我得到了SPI和DMA中斷觸發,但仍然是一個問題修復,實際上我無法接收DMA發送的所有數據。由於DMA比SPI中斷處理程序更快,我的意思是SPI中斷處理程序沒有足夠的時間來處理所有數據,所以出現這個問題呢? – fedi

+0

@fedi - 你真的可以通過DMA在SPI上發送數據的速度比使用每字節中斷讀取數據更令人驚訝嗎?嘗試設置SPI_BaudRatePrescaler以顯着減慢運行。如果這能解決問題,那麼你可能只是在輸入端「溢出」。否則,您可能會遇到其他問題。 –

+0

@Brian McFarland,你的意思是說,我們得到的問題和DMA傳輸頻率沒有關係?這可能不是我身邊的一個很好的評論,但這是我在第一面想到的, – fedi

0

確保你沒有SPI ISR中讀取接收的字節,如果你這樣做,這將導致DMA不會找到的字節被複制。 我的意思是,DMA和SPI是試圖讀取同一個緩衝區的兩個資源,你不知道它們中的哪一個會首先得到字節。 此外,DMA工作時,仍然SPI SPI ISR標誌上升,如果SPI讀取字節該標誌將被清除,導致DMA將無法正常工作。