Can low jitter be achieved with STM32 microcontroller

Hi,

I try to collect what I learn in https://github.com/jmf13/Const_DSP_I2S_DAC/wiki.

I tried to summarize what I learned about Eclipse in https://github.com/jmf13/Const_DSP_I2S_DAC/wiki/Start-a-OpenStm32-project-from-a-template-example. Three of the bullets are:

  • Update the links to the include headers in Project Properties: C/C++ General>Paths and Symbols>Includes tab>GNU C
  • Update the links to the libraries in Project Properties: C/C++ General>Paths and Symbols> tab Library Paths
  • Check the Resource>Linked resources>Linked resources tab
I'm surprized that It doesn't works on your setup, but this bare minimum experiment is very basic and if the discrepency between the 2 clocks is too big, then it will not cope with the difference. The strategy in sdr_widget is better and worth trying. You may have other ideas.


What is not good yet in my code is that the feedback is a global variable from the application side toward the usb_audio code. It would be much better to have the first circular buffer inside the usb_audio part and manage the feedback there locally. The API needs to be slightly adjusted.


By the way, I could get a hand on a nucleo stm32F746 board, so I have now the hardware to experiment with the ISAI :)


Best regards,


JMF
 
Just to check, are you using the code from the Latest commit 01cce4b 6 days ago?

Code is working with my windows10 and Linux

The code in usb_audio.c shall contain :

Code:
static uint8_t  USBD_AUDIO_IsoINIncomplete (USBD_HandleTypeDef *pdev, uint8_t epnum)                       {                           // ?? I don't understand that part                       	//This ISR is executed every time when IN token received with "wrong" PID. It's necessary                           //to flush IN EP (feedback EP), get parity value from DSTS, and store this info for SOF handler.                           //SOF handler should skip one frame with "wrong" PID and attempt a new transfer a frame later.                        
                          // I've been working on the Isoc incomplete issue... And got pretty good idea, which solved this problem.                           // At the isoc incomplete interrupt, I mark the current pid (last bit of frame number).                           // At the SOF interrupt, I test if current frame has the same parity, and when it's true,                           // transmit the feedback endpoint data. This way is 100% working.                        
                          USB_OTG_GlobalTypeDef *USBx = pdev->pData;                           //?? Not sure that the flushing of the EP is needed                           USBD_LL_FlushEP(pdev,AUDIO_IN_EP);                           /* EP disable, IN data in FIFO */                           USBx_INEP(AUDIO_IN_EP&0x7f)->DIEPCTL = (USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK);                           //USBx_INEP(epnum)->DIEPCTL = (USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK);                           /* EP enable, IN data in FIFO */                           USBx_INEP(AUDIO_IN_EP&0x7f)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);                           //USBx_INEP(epnum)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);                        
                          feedbacktable[0] = feedback_data;                           feedbacktable[1] = feedback_data >> 8;                           feedbacktable[2] = feedback_data >> 16;                           //feedbacktable[0]= 0x00;                           //feedbacktable[1]= 0x00;                           //feedbacktable[2]= 0x0C;                           //feedbacktable[0]= 0x9A;                           //feedbacktable[1]= 0xF9;                           //feedbacktable[2]= 0x0B;                        
                          USBD_LL_Transmit(pdev, AUDIO_IN_EP, (uint8_t *) &feedbacktable, 3);                        
                          //dpid = ((((USBx_DEVICE->DSTS))>>8)&((uint32_t)0x00000001));                        
                          SOF_num=0;                           /* if (flag)                           {                              flag=0;                              USBD_LL_FlushEP(pdev,AUDIO_IN_EP);                           }; */                           return USBD_OK;                       }
 
I cannot believe, but this approach works good on my old project. I have removed all excess code, declined excess buffer (called Audio[]) and it works pretty well on my W7 host.
Feedback is done by averaging (moving average - it's a kind of FIR) of TIM2->CCR1 value over the number of frames, given by 1<<SOF_RATE. Feedback value oscillates a bit near value 0x0C0077
 
Hi,

Good news. I tested yesterday my code on a W7 machine, and it was also working there. I could not post as the forum was not working properly.

Did you identified the cause of your earlier issues?

I understand that you used a different approach for the feedback, based on TIM2->CCR1. My experience is that a very basic strategy (inspired from sdr_widget) with 2 fixed feedback values, one above the target and one below the target, exchaged based on position in the buffer also works pretty well.

I programed the LEDs to give the position in the buffer and I can see that we oscillate, as expected between the Low and High thresholds without ever reaching the LL or HH.

JMF
 
As for me, it's a step to open-source UAC2 on FPGA with external ULPI PHY only (native UAC, not FTDI-based). Say, multichannel I/O board with selectable I2S/AC97/HDA interfaces. At present time, there exists working example, which acts as CDC ACM device at high-speed. Sorry for offtop.
 
Hi,

Here is a link to download my exe files:
https://dl.dropboxusercontent.com/u/29484066/Debug.zip

As I don't know what is the good file, I put the bin and .elf files. It is intended to run on the Stm32F4 discovery board.

LED codes:
LED3 = is below Low Low buffer threshold user button pressed and DSP biquad cascasd active
LED4 = is below Low buffer threshold
LED6 = is about the inactive operation of the board (provisions for DSP treatment), when the board is waiting to fill a new buffer.

JMF
 
Interesting... What means the -O0 flag? Code in interrupts can be tricky and I had to play with volatile types to get it wok. Could it be related?

I have no glitches here (I feel): do you see the LED4 and LED5 light alternatly? It would demonstrate that the buffer slowly drifts between the Low and Up Thresholds, going up and then down, and then up... in relation with the selected feedback value.

JMF
 
It's version with correct feedback and external MCLK=12.288 Mhz. Connect it to PC7, PC9 soldered together (or change the code).
//768kHz in archive's name means sampling frequency of FM MPX signal, which is generated on PA5 :) also it can generate FM RF signal with AD9951 connected.
Sorry, can't attach archive, take it there: https://drive.google.com/open?id=0B-j5bkNbrAIRUlFtNnlCOHExVTg
 
Last edited:
Hi Romanetz,

I think that you are very far in front of us in mastering the stm32 and USB concepts :). I hope that I will learn a lot in the process.

How do you change the slew rate of the USB data lines? It this related to tsome clock configuration or other type of parameter?

Impressed by your video. How do you record those type of video?

The OK behaviour is what I have here with my set-up, music reader (Foobar or VLC), and the way I proceed.

Here, the soft is OK in nominal state, but I think that my soft is still weak to manage all transitions: plug/unplug/stop music/start music...

@ypaudio: Welcome :)

JMF
 
As the project is open-source, I am glad to share my and learn your expirience. I also use the processing power of STM32, making not only "naked" USB DAC. MPX encoding part is already done. Now i'm planning to drive PCM5102 at 384 kHz. STM32 unfortunately cannot receive such stream without external USB PHY, but this is not a problem for development: Waveshare offers USB3300 boards on Aliexpress and Ebay. Native UAC2 driver will be soon introduced into Windows 10, it's being discussed and tested now in development releases.
Feedback value from timer 2 is stable and needs to be corrected very little because of limited precision: measuring time is only 1 ms. So, there exists an uncertainty of measurement by 1 LSB for each capture. Speaking in other words, masterclock frequency is rounded down every time when a capturing signal arrives.
 
Last edited: