stm32 FFT Demo

Started by tha, August 12, 2014, 04:16:13 AM

Previous topic - Next topic

tha

http://www.mediafire.com/download/u8flxzquxb4ka3j/Oscilloscope_5.rar
ลองไม่เอา touch screen แล้วใช้ switch แบบ interupt exti แทน พอกด sw ขึ้น 6 ครั้งก็เกิด hard fault ขึ้นเหมือนเดิมครับ เลยลองใส่ mask ดูว่า fault เกิดจาก memory fault, bus fault หรือ usage fault (ดูในหนังสือ Definitive Guide to Cortex-M3 M4)

  SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
  SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
  SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;

  NVIC_SetPriority(MemoryManagement_IRQn, 4);
  NVIC_SetPriority(BusFault_IRQn, 5);
  NVIC_SetPriority(UsageFault_IRQn, 6);

แล้วลองดีบักดูปรากฏว่าดีบักมาหยุดในลูป void BusFault_Handler(void) เลยลองใส่ตัวแปล bus เพื่อตรวจจับ status bit ของ fault ดู

void BusFault_Handler(void)
{
   bus = SCB->CFSR;
/* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}



ปรากฏว่า bit 9 กับ bit 15 ของ Configurable fault status register (SCB_CFSR) เซตเป็น 1 ครับ (ดูใน stm32f103 programming manual เอา)

Bit 15 BFARVALID: Bus Fault Address Register (BFAR) valid flag:
The processor sets this bit to 1 after a bus fault where the address is known. Other faults can
set this bit to 0, such as a memory management fault occurring later.
If a bus fault occurs and is escalated to a hard fault because of priority, the hard fault handler
must set this bit to 0. This prevents problems if returning to a stacked active bus fault handler
whose BFAR value has been overwritten.
0: Value in BFAR is not a valid fault address
1: BFAR holds a valid fault address.

Bit 9 PRECISERR: Precise data bus error
When the processor sets this bit is 1, it writes the faulting address to the BFAR.
0: No precise data bus error
1: A data bus error has occurred, and the PC value stacked for the exception return points to
the instruction that caused the fault.

bit 15 น่าจะเซตตาม bit 9 น่าจะเกี่ยวกับการ stack หรือเปล่า ท่านใดพอทราบบ้าง เดี๋ยวจะลองใช้แบบ switch ธรรมดาดูจะ fault อีกหรือเปล่า?

tha

http://www.mediafire.com/download/qx9xvdpa6c0y1mx/Oscilloscope_6.rar
ใช้เป็นแบบสวิทช์ธรรมดาก็ยังเหมือนเดิม  >:(

tha

มีพรายกระซิบมาบอกว่า

SampleBuffer[SamplesCount] =  (ADC_Read<<20)-0x7FFFFFFF;

อย่างนี้ไม่ถูกต้อง เพราะจะทำให้ 16 bit ล่างมีค่าด้วย ( 16 bit บนเป็นค่า Real, 16 bit ล่างเป็นค่า Imagin) ซึ่งที่ถูกค่า imagin จะเป็น 0 (มีค่า real อย่างเดียว) ซึ่งที่ถูกต้องเป็นอย่างนี้

SampleBuffer[SamplesCount] =  (ADC_Read-0x7FF)<<20;

เราลบค่า ADC_Read(12 bit) ที่อ่านได้ด้วยค่ากลาง(0x7FF) ก่อน เพื่อที่จะลดค่า sine wave ให้สวิงไปทั้งบวกและลบโดยมีค่ากลางที่ 0 จากนั้นค่อย shift left ไป 20 bit จะทำให้ค่าที่ได้ไปอยู่ SampleBuffer[] 16 bit บน(real) ส่วน 16 bit ล่าง(imagin) จะเป็น 0 ทั้งหมด อย่างนี้น่าจะถูกต้อง (ผมเปลี่ยน ADC_Read จาก unsigned int เป็น int ด้วย เพราะมีการลบกัน) ท่านอื่นว่าเป็นอย่างไรกันบ้าง?

ผลการดีบักที่ใช้  SampleBuffer[SamplesCount] =  (ADC_Read<<20)-0x7FFFFFFF;



ผลการดีบักที่ใช้  SampleBuffer[SamplesCount] =  (ADC_Read-0x7FF)<<20;




tha

Bus fault แก้หายแล้วครับ เป็นที่ stack overflow นี่เอง พอแก้ stack size จาก 0x00000100 เป็น 0x00000200 ที่ไฟล์ startup_stm32f10x_hd.c ก็สามารถเพิ่มค่าการ sampling ได้ปกติเลยครับ

/*----------Stack Configuration-----------------------------------------------*/ 
//#define STACK_SIZE       0x00000100      /*!< The Stack size suggest using even number     */
#define STACK_SIZE       0x00000200      /*!< The Stack size suggest using even number     */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];     


ส่วนตัวกำเนิดสัญญาน sine, sine wave generator for PC ก็มีค่าสวิงไปทั้งบวกและลบเลย เลยใช้ไม่ได้กับ ADC ที่ต้องการสัญญานบวกอย่างเดียว เลยต้องใช้ mcp4922 ตัวเดิม
http://www.meraman.com/htmls/en/sinTableOld.html
เว๊บที่คำนวณสัญญาน sine ให้เป็น data table mcu จะได้ไม่ต้องเสียเวลาคำนวณเอง ทำให้ทำงานได้เร็วขึ้น มีความถี่มากขึ้นนั่นเอง การตั้งค่าคำนวณควรเอาให้ full range(4095 for 12 bit) เลยจะได้ค่ากลางที่ 1.65V(0x7FF), (max 3.3V, min 0V)  ซึ่งทำให้เมื่อวัดแล้ว ลบออกด้วย 0x7FF แล้วได้ sine wave ที่มีค่ากลางที่ 0 แล้วค่อยเอาไปคำนวณ FFT ต่อไป
อาจใช้ TIM ร่วมด้วยเพื่อให้ปรับความถี่ของ sine ได้ จะได้รู้ค่าตัวกำเนิด sine ก่อนวัดเพื่อเปรียบเทียบกันได้ หรือท่านใดจะมีวีธีอื่นที่จะแนะนำบ้าง

tha

ลองใช้ cmsis dsp lib แทน ทำ fft 256 point ก็พอ ทำกราฟโชว์ spectrum แต่ละความถี่ด้วยได้ 240 ความถี่(เต็มจอก่อนไม่ครบ 256)
http://www.mediafire.com/download/6zpszy9z601atky/Oscilloscope_CMSIS.rar
เราจะคำนวณ spectrum แต่ละความถี่ให้กลับออกมาเป็น volt ได้ใหม อันนี้ผมยังไม่เข้าใจวิธีคำนวณ

tha

ขอแก้สมการตรงนี้หน่อย เนื่องจากอาเรย์เริ่มที่ 0-255 เลยต้องบวกหนึ่งเข้าไปด้วย

fundamental_frequency = (maxIndex+1)*SamplingFreq/SampleBufferSize;


การบวกขนาดก็บวกแต่เพียงข้อมูลครึ่งล่างเพียงครึ่งเดียว เพราะครึ่งบนเป็น alias อย่างนี้ถูกหรือเปล่า?

for (i = 0; i < (SampleBufferSize/2); i++)
   {
     Size += SampleBuffer_MAG[i];
   }


ลองวัดสัญญาน sine 200 Hz ปรากฏว่าเกิด alias ที่ด้านความถี่สูงด้วยตามรูป อันนี้ใครพออธิบายได้บ้างว่าทำไมถึงเกิดปรากฏการณ์นี้ขึ้น? เป็นปกติหรือเปล่าหรือว่าเราควรแก้ใขอย่างไร?





พอลองลดค่า sampling ลงมาจนเหลือ 400 Hz(สองเท่าของความถี่ที่วัดพอดี) ถึงจะมี spectrum ความถี่เพียงค่าเดียวที่ array 128 กึ่งกลางพอดี


tha

ผมลองแก้โปรแกรมให้ sampling ได้ถึง 200Hz

                        SamplingFreq = SamplingFreq - 100;
  if(SamplingFreq<200)   // min 200Hz
  SamplingFreq = 200;
  SamplingDelay = 8000000/SamplingFreq;


แล้วลองดีบักดู ลดค่า sampling ลงเท่ากับความถี่ที่วัด(200Hz) ได้ผลตามรูป



มีค่าที่ SampleBuffer_MAG[0] ไม่มีค่าที่ SampleBuffer_MAG[255] แสดงว่าค่า array ต่ำเป็นความถี่สูงส่วนค่า array สูงเป็นความถี่ต่ำ? ค่าใน array ต่ำเป็น alias ส่วนค่าใน array สูงเป็นค่าจริง? สมการความถี่ควรแก้เป็น :-\


fundamental_frequency = (25ุ6-maxIndex)*SamplingFreq/SampleBufferSize;

tha

ถ้าเราตัด spectrum ที่ความถี่ที่สูงกว่าความถี่ Nyquist(sampling frequency/2) (คิดเฉพาะ SampleBuffer_MAG[] ทางด้านสูง array 128-255) อย่างนี้ถือว่าเราทำ anti-aliasing filter หรือเปล่า? (ตัด SampleBuffer_MAG[0]-[127] ครึ่งด้านต่ำออก ไม่เอามาคิด)
http://www.mediafire.com/download/7cu54cz5wqpk06b/Oscilloscope_CMSIS_1.rar
หรือว่าเราควรทำ anti-aliasing filter ที่ hardware?