CMSIS & STDLIB & DSPLIB

Başlatan memo333, 05 Aralık 2011, 22:17:28

memo333



Herkese merhaba,

Kitlerdi şunlardı derken bayağı kafalar karışık. Aslında bu yazıyı daha önce hazırladım ancak yayınlamayabildim.

STM32 MCUları ile bazı temel kavramları üzerinde değinmek istedim çünkü çok karışıyor ve bu konuda –bence- bir kaynak eksikliği bulunmakta. Bu eksikliği gidermek için aşağıda basitçe 3 temel kavramda üzerinde duracağım:
•   CMSIS
•   Standard Peripherals Library  (STDLIB)
•   DSPLIB

STM32F4xx DSP and Standard Peripherals Library  STM32F4xx mikrokontrolcüleri için ARM firmasının CMSIS standartına uygun olarak ST tarafından geliştirilmiş  tüm donanımların sürücülerini ve temel sinyal işleme fonksiyonlarını içeren bir pakettir. Bu paket ST'nin sitesinden indirilebilir.

Cortex Microcontroller Interface Standard CMSIS ARM tarafından Cortex-M çekirdeğine yönelik farklı silikon ve yazılım sağlayıcıları için geliştirilmiş standart ve aynı zamanda kütüphanedir. Örneğin çekirdek ile ilgili tanımlamalar core_cm4.h dosyası içinde bulunmaktadır. Bir başka örnek olarak stm32f4xx.h dosyası ise ST tarafından sağlanmaktadır ve çekirdek harici tüm donanımın tanımlamarını içermektedir. CMSIS yapısı üzerinde detaylı çalışma yapılabilir, burada değinmeyeceğim.

Standard Peripherals Library  (STDLIB) donanımlar ile ilgili olan makrolar, rutinler ve veri-yapılarını içeren bir kütüphane içermektedir. Bu sayede donanım ile ilgili olarak derinlemesine olarak çalışma yapmadan kod geliştirilebilmesini sağlamaktadır. Örneğin GPIO_SetBits gibi fonksiyonlar ile register isimleri ezberlenmeden  daha kolay kod geliştirilebilmektedir. Ayrıca her bir donanım için bir takım örnekler de sunulmaktadır.

Paket içinde ayrıca CMSIS DSP-Library bulunmaktadır. DSPLIB Cortex-M cihazları ile birlikte kullanılabilecek temel sinyal işleme fonksiyonlarını içermektedir. DSPLIB tamamen C dilinde yazılmıştır ve CMSIS standartına uygun olarak geliştirilmiştir. Maksimum performans –doğal olarak- Cortex-M4F çekirdekleri ile sağlanacaktır. DSPLIB daha önceki serilerde yoktu üstünde hiç çalışamadım.

Sonuç olarak CMSIS ARM tarafından yayınlanan bir standarttır, çekirdek ile ilgilidir. Ayrıca ARM firması DSP kütüphanesi de yayınlamıştır. Bunlardan bağımsız olarak ST firması diğer firmalarda da olmayan  donanımı daha kolay kullanabilmek için bir kütüphane yayınlamıştır buna da STDLIB diyorum. STDLIB ile kayıtçılar ile fazla uğraşmadan hızlı bir şekilde kod yazabilirsiniz tabii her avantajın bir de dezavantajı vardır. Örneğin daha yavaş çalışma, daha şişkin kod vs.
   
Herkese iyi çalışmalar..
Gömülü Linux Notları --> http://linuxedu.xyz/

memo333

Gömülü Linux Notları --> http://linuxedu.xyz/

Mucit23

Konu biraz fakir kalmış. CMSIS DSP library hakkında birkaç sorum olacak.

Complex FFT ile Real FFT arasında pratikte ne gibi bir fark var. Bununla ilgili CMSIS DSP dökümanlarını karıştırıyorum ama anlayabilmiş değilim.

Ben basitçe FFT almaya çalışıyorum. FFT sonucunda çıkış verisinin boyutu 256 olacak. Giriş verisinin boyutu ise iki katı olması gerektiğinden 512 olarak ayarladım. 16Khz de 512 örnek alıp FFT işlemine tabi tutmayı hedefliyorum.

DSP Libraryde  Transform fonksiyonları içerisinde arm_cfft_radix4_f32.c ile arm_rfft_fast_f32 diye iki adet kütüphane var. Hangisiyle işlem yapacağımı anlayamadım açıkçası.

Herhangi birini kullanırken doğrudan ADC den sabit örnekleme frekansında örneğin 512 örnek alıp fonksiyona vermek yeterlimidir?

Mucit23

Bu DSP Library hakkında bir sorunum var. FFT konusunda bir problem yaşıyorum.

Timer ile sabit 44Khz frekansta ADC yi tetikleyip DMA ile 256 adet örnek alıyorum. 256 adet örnek alındığı zaman kesme oluşuyor. Kesme oluştuğu zaman FFT hesaplama işlemlerini yapıyorum.

FFT için aşağıdaki yapıyı kullanıyorum.
if(FFT_Ready_Flag)
		{
			 SampleIndex=0;
			for(i=0;i<512;i++)Input[i]=0;
			
			 for(i=0;i<ADC_SAMPLES;i=i+2) //Loading input buffer
			 {
			    Input[i]=(float32_t)((float32_t)ADCConvertedValue[SampleIndex]-(float32_t)2048.0)/(float32_t)2048.0;
				  Input[i+1]=0;//Clearing imaginary Values
				  SampleIndex++;
			 } 
			 /* Initialize the CFFT/CIFFT module */
		   arm_cfft_radix4_init_f32(&FFT_Module, FFT_SIZE, 0, 1);
		   /* Process the data through the CFFT/CIFFT module */
		   arm_cfft_radix4_f32(&FFT_Module, Input);
			 /* Process the data through the Complex Magnitude Module for calculating the magnitude at each bin */
		   arm_cmplx_mag_f32(Input, Output, FFT_SIZE);
			 /* Calculates maxValue and returns corresponding value */
			 arm_max_f32(Output, FFT_SIZE, &MaxValue, &MaxValueIndex);
			 /*Clear FFT Buffer */
			 FFT_Ready_Flag=0; 
		}


Sorun Timer'ın aktif olması durumunda işlemcinin arm_cmplx_mag_f32(Input, Output, FFT_SIZE) fonksiyonunda donup kalması. Timer kapalı iken bu durum yaşanmıyor.
İlk başta aklıma timer açıkken kesme çok sık kesme oluşup arm_cmplex_mag_f32 fonksiyonunda işlemlerin sekteye uğraması. Ama böyle bir durum olmaması lazım çünkü kesme yaklaşık 6 ms aralıklarla oluşuyor ve kesme oluştuktan sonra hemen FFT alma işlemlerini hallediyorum.

Normalde zaten yukarıda verdiğim kodlar 140us içerisinde işlenmiş oluyor. bunu timer kapalı iken ölçüyorum.

DSP Library için Compile and program options bölümünde aşağıdaki tanımlamaları yaptım.

ARM_MATH_CM7, __FPU_PRESENT=1

Bu aşamadayken derlemede problem yok. Donmasının sebebini anlayamadım. Yukarıdaki kodlar çalışıyorken kesme zaten oluşmuyor. Hatta test için FFT işlemlerine başlamadan önce Timeri kapattım FFT işlemleri bitince tekrar açtım ama olmadı.

Ne olabilir sizce sorun?  Daha önce DSP library ile çalışma yapan oldumu?

z

Yazdıklarınla alakalı değil gene de hatırlatmak isterim. Matematik işlemcinin clockunu kapatıp duruyorduk onunla ilgisi olabilirmi?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Mucit23

Hocam FPU'dan mı bahsediyorsunuz tam anlayamadım aslında.

FPU'nun aktif olması için __FPU_PRESENT=1 tanımlaması yeterli değilmi?

Keilde debug olayınıda anlayabilmiş değilim. DMA kesmesinin oluştuğunu anlayabilmek için bir pini toggle yapıyorum ve osiloskop ile o pini takip ediyorum sürekli. Kesme oluştumu takip edebiliyorum.

Normal çalışmada mesela eğer arm_cmplx_mag_f32 fonksiyonu yok iken işlemci normal olarak çalışıyor dma kesmesi vs tam olarak ayarladığım gibi çalışıyor. Ama bu arm_cmplx_mag_f32 fonksiyonu eklediğinde debug sırasında 2-3 satır aralıklarla HAL_DMA_IRQHandler fonksiyonuna gidiyor.
Gerçektende öyle Osiloskop ile ölçtüğümde 0.470us aralıklarla HAL_DMA_IRQHandler kesmesi oluşuyor.

Timer açık olsun. Main içerisinde de sadece arm_cmplx_mag_f32 fonksiyonu olsun dediğim gibi 0.470us DMA kesmesi oluşuyor.
Timer kapalı olunca çalışmada herhangi bir sıkıntı yok kesme felan oluşmuyor.

arm_cmplx_mag_f32  fonksiyonunun içeriği aşağıdaki gibi
/* ----------------------------------------------------------------------    
* Copyright (C) 2010-2014 ARM Limited. All rights reserved.    
*    
* $Date:        19. March 2015
* $Revision: 	V.1.4.5
*    
* Project: 	    CMSIS DSP Library    
* Title:		arm_cmplx_mag_f32.c    
*    
* Description:	Floating-point complex magnitude.    
*    
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
*  
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions
* are met:
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the 
*     distribution.
*   - Neither the name of ARM LIMITED nor the names of its contributors
*     may be used to endorse or promote products derived from this
*     software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.  
* ---------------------------------------------------------------------------- */

#include "arm_math.h"

/**    
 * @ingroup groupCmplxMath    
 */

/**    
 * @defgroup cmplx_mag Complex Magnitude    
 *    
 * Computes the magnitude of the elements of a complex data vector.    
 *   
 * The <code>pSrc</code> points to the source data and    
 * <code>pDst</code> points to the where the result should be written.    
 * <code>numSamples</code> specifies the number of complex samples    
 * in the input array and the data is stored in an interleaved fashion    
 * (real, imag, real, imag, ...).    
 * The input array has a total of <code>2*numSamples</code> values;    
 * the output array has a total of <code>numSamples</code> values.    
 * The underlying algorithm is used:    
 *    
 * <pre>    
 * for(n=0; n<numSamples; n++) {    
 *     pDst[n] = sqrt(pSrc[(2*n)+0]^2 + pSrc[(2*n)+1]^2);    
 * }    
 * </pre>    
 *    
 * There are separate functions for floating-point, Q15, and Q31 data types.    
 */

/**    
 * @addtogroup cmplx_mag    
 * @{    
 */
/**    
 * @brief Floating-point complex magnitude.    
 * @param[in]       *pSrc points to complex input buffer    
 * @param[out]      *pDst points to real output buffer    
 * @param[in]       numSamples number of complex samples in the input vector    
 * @return none.    
 *    
 */

void arm_cmplx_mag_f32(
  float32_t * pSrc,
  float32_t * pDst,
  uint32_t numSamples)
{
  float32_t realIn, imagIn;                      /* Temporary variables to hold input values */

#ifndef ARM_MATH_CM0_FAMILY

  /* Run the below code for Cortex-M4 and Cortex-M3 */
  uint32_t blkCnt;                               /* loop counter */

  /*loop Unrolling */
  blkCnt = numSamples >> 2u;

  /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    
   ** a second loop below computes the remaining 1 to 3 samples. */
  while(blkCnt > 0u)
  {

    /* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
    realIn = *pSrc++;
    imagIn = *pSrc++;
    /* store the result in the destination buffer. */
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);

    realIn = *pSrc++;
    imagIn = *pSrc++;
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);

    realIn = *pSrc++;
    imagIn = *pSrc++;
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);

    realIn = *pSrc++;
    imagIn = *pSrc++;
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);


    /* Decrement the loop counter */
    blkCnt--;
  }

  /* If the numSamples is not a multiple of 4, compute any remaining output samples here.    
   ** No loop unrolling is used. */
  blkCnt = numSamples % 0x4u;

  while(blkCnt > 0u)
  {
    /* C[0] = sqrt(A[0] * A[0] + A[1] * A[1]) */
    realIn = *pSrc++;
    imagIn = *pSrc++;
    /* store the result in the destination buffer. */
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);

    /* Decrement the loop counter */
    blkCnt--;
  }

#else

  /* Run the below code for Cortex-M0 */

  while(numSamples > 0u)
  {
    /* out = sqrt((real * real) + (imag * imag)) */
    realIn = *pSrc++;
    imagIn = *pSrc++;
    /* store the result in the destination buffer. */
    arm_sqrt_f32((realIn * realIn) + (imagIn * imagIn), pDst++);

    /* Decrement the loop counter */
    numSamples--;
  }

#endif /* #ifndef ARM_MATH_CM0_FAMILY */

}

/**    
 * @} end of cmplx_mag group    
 */


Bu fonksiyon neden böyle davranıyor açıklayabilecek olan var mı? Timer ile ne ilgisi var?



z

Timer int rutininde timer int flağını siliyormusun?

Silmeden çıkıyorsan ha bire interrupta giriyordur.

Aslında debug olayını yalayıp yutmanız gerekiyor. CPU ne yapıyor ne ediyor kitleniyorsa nerde kitleniyor vs her şey belli.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Mucit23

Alıntı yapılan: z - 19 Ocak 2016, 11:03:35
Aslında debug olayını yalayıp yutmanız gerekiyor. CPU ne yapıyor ne ediyor kitleniyorsa nerde kitleniyor vs her şey belli.

Abi seni yakalamışken neden öğretmiyorsun diye sormadan edemiyorum :)
Şöyle bir ders niteliğinde F4 için keildeki debug inceliklerini anlatsan bize ne güzel olur. Ciddi anlamda bu tür işlemcilerle uğraşanların bilmesi gereken bir olay. Keilin bir çok özelliği var bu konuda. Doğru dürüst hiçbirini bilmiyorum.

Aslında @memo333 hocam belki konuya dahil olur diye umutlanıyorum. Biraz DSP library hakkında bilgi verse ne güzel olur.

Ben şimdilik timer ve ADC kullanmaktan vazgeçtim.
STM32F7 disco üzerinde mikrofon ve harici ses girişi var. Az önce onları çalıştırdım. Şimdi Line IN girişinden ses uygulayabiliyorum. Harici mikofonlarda gayet güzel çalışıyor. Birtek ses çıkışını denemedim.

Yalnız gelen mikrofondan veya harici ses girişinden gelen değerlerde bir gariplik var. Normalde gelen değerlerin  16bit signed int türünden olmasını beklersin ama fonksiyon fonksiyon uint16_t türünde bir bufferi kabul ediyor.

Mikrofondan gelen değerleri ekrana yazdırdığımda sürekli 65535'e gidip geliyor. Yani gelen veri işaretli sayı türünde sanırım. Bir daha signed int türüne cevirmek gerekecek herhalde.


CoşkuN

Exception handler fonksiyonların tanımlı mı? Her birine bir breakpoint koyup deneyebilirsin. Hardfault exception yiyor olabilir.