2016-08-04 43 views
0

私はSTM32f405を持っています。このタスクは、SPIでデータを送信し、DMAでプロセッサ時間を節約することです。使用されるSPIはピンPA4〜PA7のSPI1です。私はDMAのためにDMA2チャンネル3から3番目のストリームを選択しました。その考えは、CS信号をアクティブにして、DMAによって自動的に転送されるメモリにいくつかのデータを保存することです。ハンドラを使用してCSを無効にします。DMAでデータを送信するためのSTM32f405 SPIの設定方法は?

static void SPI_Config(void) { 
    GPIO_InitTypeDef GPIO_InitStructure; 
    SPI_InitTypeDef SPI_InitStructure; 
    DMA_InitTypeDef DMA_Init_Structure; 
    NVIC_InitTypeDef NVIC_InitStructure; 
    /* Enable the SPI clock */ 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); 
    /* Enable GPIO clocks */ 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 
    /* Enable DMA clock */ 
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 
    /* SPI GPIO Configuration --------------------------------------------------*/ 
    /* GPIO Deinitialisation */ 
    GPIO_DeInit(GPIOA); 
    /* Connect SPI pins to AF5 */ 
// GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1); //SS 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); //SCK 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); //MISO 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); //MOSI 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //SCK 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MISO 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //MOSI 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //SS 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    //DMA Globul Interrupt 
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure); 

    //DMA Configuration 
    DMA_DeInit(DMA2_Stream3); 
    DMA_Cmd(DMA2_Stream3, DISABLE); 
    while (DMA1_Stream0->CR & DMA_SxCR_EN); 
    DMA_Init_Structure.DMA_BufferSize = 0; 
    DMA_Init_Structure.DMA_Channel = DMA_Channel_3; 
    DMA_Init_Structure.DMA_DIR = DMA_DIR_MemoryToPeripheral; 
    DMA_Init_Structure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
    DMA_Init_Structure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; 
    DMA_Init_Structure.DMA_Memory0BaseAddr = (uint32_t)(&spi_tx_val); 
    DMA_Init_Structure.DMA_MemoryBurst = DMA_MemoryBurst_Single; 
    DMA_Init_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    DMA_Init_Structure.DMA_MemoryInc = DMA_MemoryInc_Disable; 
    DMA_Init_Structure.DMA_Mode = DMA_Mode_Circular; 
    DMA_Init_Structure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI1->DR)); 
    DMA_Init_Structure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    DMA_Init_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    DMA_Init_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    DMA_Init_Structure.DMA_Priority = DMA_Priority_High; 
    DMA_Init(DMA2_Stream3,&DMA_Init_Structure); 

    //SPI Configuration 
    SPI_I2S_DeInit(SPI1); 
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; 
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; 
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //AD5620 doku page 18 falling edge of SCLK 
    SPI_InitStructure.SPI_CRCPolynomial = 0; //x_8+x_2+x_1+1 in python hex(2**8+2**2+2+1) 
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //AD5620 input register is 16 bit 
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; 
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; 
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 
    SPI_Init(SPI1, &SPI_InitStructure); 




} 

int8_t Analog_Out_Config(uint32_t target_reg_val) { 
    uint16_t power_on_status; 
    target_reg_val = target_reg_val; 
    SPI_Config(); 
// SPI_Cmd(SPI1, ENABLE); 
// power_on_status=PowerOn_AD5750_OutDriver(); 
// if(power_on_status) { 
     //enable dma interrupt 
//  SPI_Cmd(SPI1, DISABLE); 
     DMA_ITConfig(DMA2_Stream3,DMA_IT_TC,ENABLE); 
     DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3|DMA_FLAG_DMEIF3|DMA_FLAG_TEIF3|DMA_FLAG_HTIF3|DMA_FLAG_TCIF3); 
     DMA_Cmd(DMA2_Stream3, ENABLE); 
     SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx, ENABLE); 
     SPI_Cmd(SPI1, ENABLE); 

     return power_on_status&0x07; 
// }else { 
//  return -1; 
// } 
} 
void Analog_Output(uint32_t measured_reg_val) { 
    val=0x7ff; 
    ACTIVATE_CS_DAC(); 
    spi_tx_val=val; 
} 

void DMA2_Stream3_IRQHandler(void) { 
    if(DMA_GetITStatus(DMA2_Stream3,DMA_IT_TCIF3)!=RESET) { 
     DMA_ClearITPendingBit(DMA2_Stream3,DMA_IT_TCIF0|DMA_IT_HTIF0); 
     DEACTIVATE_CS_DAC(); 

    } 
} 

int main(void) 
{ 
    target_reg_val=14; 
    measured_reg_val=12; 
    Analog_Out_Config(target_reg_val); 
    while (1) 
    { 
     for(val=-target_reg_val;val<target_reg_val;val++) { 
      Analog_Output(val); 
      for(i=0;i<1000;i++); 
     } 

    } 
} 

私はDMA2_Stream3_IRQHandlerがアクティブ化されることはありませんことを発見したデバッガで:ここではコードです。リファレンスマニュアルによると、DMAはSPI_DRレジスタからのTXEフラグが1のときにデータを転送する必要があります。また、SPI_CR2からのTXDMAENフラグもセットされました。私はDMA S3CRレジスタもチェックし、フラグTCIEとENもセットされていました。さらに、DMA2_Stream3_IRQHandler関数はメイン関数から見えます。まだDMA2_Stream3_IRQHandlerはアクティブ化されませんでした。

UPDATE:手動でDMA2_S3CRレジスタのENビットをリセットすると、DMA2_Stream3_IRQHandlerがトリガされます。リファレンスマニュアルによれば、このビットはハードウェアによってクリアされる:転送エラーがAHBマスタバス上に発生した場合

  • 転送のDMA側の
  • を(設定できる状態ストリーム)
  • メモリAHBポート上のFIFOしきい値は、バースト

の サイズと互換性がありません、私もまだデバッガDMA2_Stream3_IRQHandlerによる介入なしに、SPI_ConfigとAnalog_Out_Configを変更したトリガされることはありません。 DMAが転送を開始していないため、何らかの理由でDMAを終了できないようです。 DMAが転送をトリガーしているかどうかを知るにはどうすればよいですか?

+0

TL; DRただし、実際の転送が開始される前に周辺機器でDMAを有効にする必要があります。 1つの側面は、CPUとDMA転送を(簡単に)混在させることができないことです。 (これは例えばUSARTの場合も同様である)。 – Olaf

+0

私はあなたがここにすべてのコードを書いていないと仮定していますが、質問では、DMAをセットアップする場所で 'SPI_Config'を呼び出すことはありません。実際にそうであれば、それはおそらく動作しません。 – rjp

+0

@rjp SPIに専用のDMAを含むSPIを設定するためにSPI_Configを使用しています。しかし、私はAnalog_Out_Config機能でDMAを有効にしています。私はこれまで、ADCのようなシステムの他の部分についてこれを行ってきましたが、これは決して問題にはなりませんでした。 –

答えて

0

DMA_ModeからDMA_NORMALまでのDMA構成構造があります。周辺フロー制御であるDMA_PFCTRLに設定する必要があります。これにより、DMAは、連続して実行するのではなく、設定したペリフェラルからの信号を待つことになります。しかし、この設定がなければ、SPI_DRはDMA転送のすべてのメモリ設定を連続してダンプする必要があるため(最初のワードをシフトしているため)、SPIバスから1,2ワードが出てくることが予想されます。 。

また、周辺機器(SPI1DMA2)がリセットされていないことを確認してください。私はクロックを無効にすることがわかりますが、STがその呼び出しで周辺機器のリセットを解除するかどうかはわかりません。

ノート:私はリファレンスとしてSTM32F2xx DMAペリフェラルを使用しましたが、STM32F4xxペリフェラルはスーパーセットである傾向があります。また、リファレンスとして使用したものとは異なるST周辺ライブラリを使用しているようです。

+0

F4周辺機器は、F2の周辺機器と実質的に同じです(いくつかの機器は...でしたが...)。追加の注意として:私はゴミ箱STlibの使用を強く拒否します。それはちょうどbloatwareであり、不必要に物事を複雑にします。それを「HAL」と命名するのは単なる冗談ですが、とにかくハードウェアを知っておく必要があります。周辺機器の定義ヘッダーを使用し、独自のドライバを作成してハードウェアアクセスをカプセル化してください。 – Olaf

+0

それは私たちがやったことですが、数年経っています。私はKinetisファミリに移りました.KinetDKファミリには実際に使用できるドライバがいくつかあります(ただし、Kinetisの周辺機器に移植したポータブルフレームワークはまだあります)。 – rjp

+0

@両方のファミリを実際に(そしてかなり他のものも)プログラムしました。それでも、ハードウェアに直接アクセスできるドライバに対応するライブラリを表示する必要があります。 1つの大きな問題は、これらのライブラリがしばしば、私が好むものと一致しないシステムアーキテクチャを強制することです(さまざまなプロジェクトで優れていることが証明されています)。これらのライブラリは、特にCortex-M3/4/7の割り込み優先度、非常に巧妙なマルチスレッド対応など、古いプログラミングスタイルに固執する傾向があります。多分。しかし、私は彼らには良い理由があります。 – Olaf

関連する問題