2017-09-18 108 views
2

現在、STM32F303REチップを搭載したNucleo-64ボードを使用しています。プログラミングのために、私はSTM32パッケージでArduino IDEを使用します。私はHALを避けたいと思っています。なぜなら、同時にレジスタとライブラリ関数を学ばなければならないときは、むしろ混乱していると思うからです。STM32F303:DMA付きADCは数回しか動作しません

私は4つの入力信号を5.1 Msps(最大F303)でサンプリングできるようにしたいと考えています。私の計画はADCを稼動させ続けることでした。次に、サンプルを取りたいときは、DMAフラグをリセットし、キャプチャしたいサンプル数にカウンタ(CNDTR-Register)を設定します。

これを達成するための私の試行を以下に示します。基本的にはほとんど動作していますが、限られた時間しかありません。どのくらいの頻度で動作するかは、プログラムの特定の部分に入力するランダムなスリープ値に依存するようです。 例:takeSamples()関数の後に10msの遅延を入力すると、プログラムは41回のメインループで動作し、スタックされます。

DMA-CNDTRレジスタは1つの値だけ減少し、そこにとどまります。したがって、プログラムはレジスタ値がゼロになるのを待っていますが、これは決して起こりません。 ADCは、全体の時間をサンプリングしている、私はちょうど良いADCのデータレジスタを読み取ることができます。

誰かが、DMAが一定の時間後にデータ転送を停止する原因となる考えがありますか?

は、ここでプログラムの関連する部分です:

void setup() { 
    Serial.begin(57600); 

    // Enable clocks 
    RCC->AHBENR |= (1 << 17); // GPIOA 
    RCC->AHBENR |= (1 << 18); // GPIOB 

    // Set ADC pins to analog input 
    GPIOA->MODER |= (0b11 << 0); // PA0 for ADC1 
    GPIOA->MODER |= (0b11 << 8); // PA4 for ADC2 
    GPIOB->MODER |= (0b11 << 2); // PB1 for ADC3 
    GPIOB->MODER |= (0b11 << 24); // PB1 for ADC4 

    initClock(); 
    DMA_init(); 
    ADC_init(); 

    // Start conversion 
    ADC1->CR |= (1 << 2); 
    ADC3->CR |= (1 << 2); 
} 

void initClock() 
{ 
    FLASH->ACR |= (0b10 << 0); // add two wait states 

    RCC->CR |= (1 << 18); // Bypass HSE, use external clock signal from STLink instead 

    RCC->CR &= ~(1 << 24); // turn off PLL 
    delay(100); 
    RCC->CFGR |= (0b0000 << 4); // Do not divide system clock 
    RCC->CFGR |= (0b0111 << 18); // PLL multiply = 9 
    RCC->CFGR |= (0b10 << 15); // use HSE as PLL source 
    RCC->CFGR |= (1 << 10); // not divided 
    delay(100); 
    RCC->CR |= (1 << 24); // turn on PLL 
    delay(100); 
} 

void ADC_init(void) { 

    RCC->CFGR2 |= (0b10000 << 4); // Prescaler 
    RCC->CFGR2 |= (0b10000 << 9); // Prescaler 
    RCC->AHBENR |= (1 << 28); // turn on ADC12 clock 
    RCC->AHBENR |= (1 << 29); // turn on ADC34 clock 

    // Set ADC clock 
    ADC12_COMMON->CCR |= (0b01 << 16); // 0b01 
    ADC34_COMMON->CCR |= (0b01 << 16); // 0b01 


    // disable the ADC 
    ADC1->CR &= ~(1 << 0); 
    ADC2->CR &= ~(1 << 0); 
    ADC3->CR &= ~(1 << 0); 
    ADC4->CR &= ~(1 << 0); 

    // enable the ADC voltage regulator 
    ADC1->CR &= ~(1 << 29); 
    ADC2->CR &= ~(1 << 29); 
    ADC3->CR &= ~(1 << 29); 
    ADC4->CR &= ~(1 << 29); 

    ADC1->CR |= (1 << 28); 
    ADC2->CR |= (1 << 28); 
    ADC3->CR |= (1 << 28); 
    ADC4->CR |= (1 << 28); 

    // start ADC calibration cycle 
    ADC1->CR |= (1 << 31); 
    // wait for calibration to complete 
    while (ADC1->CR & (1 << 31)); 

    // start ADC calibration cycle 
    ADC2->CR |= (1 << 31); 
    // wait for calibration to complete 
    while (ADC2->CR & (1 << 31)); 

    // start ADC calibration cycle 
    ADC3->CR |= (1 << 31); 
    // wait for calibration to complete 
    while (ADC3->CR & (1 << 31)); 

    // start ADC calibration cycle 
    ADC4->CR |= (1 << 31); 
    // wait for calibration to complete 
    while (ADC4->CR & (1 << 31)); 

    // enable the ADC 
    ADC1->CR |= (1 << 0); 
    ADC2->CR |= (1 << 0); 
    ADC3->CR |= (1 << 0); 
    ADC4->CR |= (1 << 0); 

    while (!(ADC1->ISR & (1 << 0))); 
    while (!(ADC2->ISR & (1 << 0))); 
    while (!(ADC3->ISR & (1 << 0))); 
    while (!(ADC4->ISR & (1 << 0))); 

    // Select ADC Channels 
    ADC1->SQR1 = (1 << 6); 
    ADC2->SQR1 = (1 << 6); 
    ADC3->SQR1 = (1 << 6); 
    ADC4->SQR1 = (3 << 6); 

    // Set sampling time for regular group 1 
    ADC1->SMPR1 |= (0b000 << 3); // 0b000 -> 1.5 clock cycles, shortest available sampling time 
    ADC2->SMPR1 |= (0b000 << 3); 
    ADC3->SMPR1 |= (0b000 << 3); 
    ADC4->SMPR1 |= (0b000 << 3); 

    // Regular sequence settings 
    ADC1->SQR1 |= (0b0000 << 0); // One conversion in the regular sequence 
    ADC2->SQR1 |= (0b0000 << 0); 
    ADC3->SQR1 |= (0b0000 << 0); 
    ADC4->SQR1 |= (0b0000 << 0); 

    // Enable continuous conversion mode 
    ADC1->CFGR |= (1 << 13); // Master ADC1 + ADC2 
    ADC3->CFGR |= (1 << 13); // Master ADC3 + ADC4 

    ADC12_COMMON->CCR |= (0b00110 << 0); 
    ADC34_COMMON->CCR |= (0b00110 << 0); 

    // DMA mode 
    ADC12_COMMON->CCR |= (0 << 13); // 0 -> One Shot; 1 -> Circular 
    ADC34_COMMON->CCR |= (0 << 13); 

    // DMA mode for 12-bit resolution 
    ADC12_COMMON->CCR |= (0b10 << 14); 
    ADC34_COMMON->CCR |= (0b10 << 14); 
} 

void DMA_init(void) { 

    // Enable clocks 
    RCC->AHBENR |= (1 << 0); // DMA1 
    RCC->AHBENR |= (1 << 1); // DMA2 

    // Transfer complete interrupt enable 
    DMA1_Channel1->CCR |= (1 << 1); 
    DMA2_Channel5->CCR |= (1 << 1); 

    // Memory increment mode 
    DMA1_Channel1->CCR |= (1 << 7); 
    DMA2_Channel5->CCR |= (1 << 7); 

    // Peripheral size 
    DMA1_Channel1->CCR |= (0b11 << 8); 
    DMA2_Channel5->CCR |= (0b11 << 8); 

    // Memory size 
    DMA1_Channel1->CCR |= (0b11 << 10); 
    DMA2_Channel5->CCR |= (0b11 << 10); 

    // Number of data to transfer 
    DMA1_Channel1->CNDTR = uint32_t(maxSamples); 
    DMA2_Channel5->CNDTR = uint32_t(maxSamples); 

    // Peripheral address register 
    DMA1_Channel1->CPAR |= (uint32_t)&ADC12_COMMON->CDR; 
    DMA2_Channel5->CPAR |= (uint32_t)&ADC34_COMMON->CDR; 

    // Memory address register 
    DMA1_Channel1->CMAR |= uint32_t(&dataPoints1232); 
    DMA2_Channel5->CMAR |= uint32_t(&dataPoints3432); 

    // Reset flags 
    DMA1->IFCR |= 0xFF; 
    DMA2->IFCR |= 0xFF; 
} 

void takeSamples(void) { 

    // Reset flags 
    DMA1->IFCR |= (0b1111111111111111111111111111111 << 0); 
    DMA2->IFCR |= (0b1111111111111111111111111111111 << 0); 

    // Number of data to transfer 
    DMA1_Channel1->CNDTR = uint32_t(maxSamples); 
    DMA2_Channel5->CNDTR = uint32_t(maxSamples); 

    delay(10); // does not work without this random delay 

    elapsedTime = micros(); 
    // Enable DMA 
    DMA1_Channel1->CCR |= (1 << 0); 
    DMA2_Channel5->CCR |= (1 << 0); 

    while ((DMA1_Channel1->CNDTR > 0) || (DMA2_Channel5->CNDTR > 0)) 
    } 

    elapsedTime = micros() - elapsedTime; 

    // Reset flags 
    DMA1->IFCR |= (0b1111111111111111111111111111111 << 0); 
    DMA2->IFCR |= (0b1111111111111111111111111111111 << 0);; 

    DMA1_Channel1->CCR &= ~(1 << 0); 
    DMA2_Channel5->CCR &= ~(1 << 0); 

    // ADC stop conversion 
    ADC1->CR |= (1 << 4); 
    ADC3->CR |= (1 << 4); 

    while ((ADC1->CR & (1 << 2)) || (ADC3->CR & (1 << 2))); 

    ADC12_COMMON->CCR &= ~(0b10 << 14); 
    ADC34_COMMON->CCR &= ~(0b10 << 14); 

    ADC12_COMMON->CCR |= (0b10 << 14); 
    ADC34_COMMON->CCR |= (0b10 << 14); 

    // ADC start conversion 
    ADC1->CR |= (1 << 2); 
    ADC3->CR |= (1 << 2); 
} 

void loop() { 
    takeSamples(); 
    Serial.print("Elapsed time: "); 
    Serial.println(elapsedTime); 
} 

私はこの問題に関して任意のヒントやヒントのために本当にthankfullだろう!

挨拶 ベニー

編集:私はまた、STM32F401チップで核 - 64と同じ問題がありました。一方、STM32F4ディスカバリーはうまくいきました。私のF103フライトコントローラボードでも同様の問題はありませんでした。

+0

1.まず人間が判読できる値を使用し始めます。 –

+0

2. arduino IDEをあきらめて、openSTM32をインストールしたeclipseなど、まともなものを使い始める。 –

+0

3. CMSIS定義を使用する –

答えて

2

例としては、タイマーでトリガーされた簡単な変換があります。

void ReadChannels(int channel, size_t nsamples, uint8_t *obuff) 
{ 
    TIM1 -> CR1 = 0; 
    TIM1 -> CR2 = 0; 
    TIM1 -> PSC = PSC; 
    TIM1 -> ARR = ARR; 
    TIM1 -> EGR |= TIM_EGR_UG; 

    DMA1_Channel1 -> CPAR = (uint32_t)&(ADC1 -> DR); 
    DMA1_Channel1 -> CMAR = (uint32_t)obuff; 
    DMA1_Channel1 -> CNDTR = nsamples; 
    DMA1_Channel1 -> CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN; 

    ADC1 -> CFGR = ADC_CFGR_DMAEN | (0b10 << ADC_CFGR_RES_Pos) | (9 << ADC_CFGR_EXTSEL_Pos) | (0b01 << ADC_CFGR_EXTEN_Pos); 
    ADC1 -> SMPR1 = 0; 
    ADC1 -> SMPR2 = 0; 

    ADC1 -> SQR1 &= ~(ADC_SQR1_L_Msk); 
    ADC1 -> SQR1 &= ~(ADC_SQR1_SQ1_Msk); 

    ADC1 -> SQR1 |= channel << ADC_SQR1_SQ1_Pos); 
    ADC1 -> CR |= ADC_CR_ADSTART; 

    TIM1 -> CR2 |= TIM_CR2_MMS_1; 
    TIM1 -> CR1 |= TIM_CR1_CEN; 

    DMA1_Channel1 -> CCR = 0; 
    TIM1 -> CR1 = 0; 
} 
+0

ありがとうございました!定義を使用すると、プログラムの読みやすさが向上します。たぶん、問題はコード自体から別の質問に分けることができます:何がADC + DMAをしばらく働かせることができましたか?しかし、ある程度の完全なDMAサイクルがDMAがデータを転送するのを止めたら? ammountは、何らかの形で私がプログラムのさまざまな部分に挿入する睡眠のインターバルに依存しています。多分、異なるクロックでいくつかの同期問題? – Pixel

+0

質問は複雑で一般的には答えられません。問題が発生したときにプログラムをデバッグし、DMA、ADC、およびTIMレジスタの値をチェックして、実際のステータスとエラーを確認する必要があります。 –

関連する問題