Skip to main content
Graduate II
December 21, 2025
Question

Trying to source a 12.288MHz clock for STM32L433

  • December 21, 2025
  • 7 replies
  • 297 views

 

I am trying to source a 12.288MHz clock for an STM32L433 but having difficulties finding something.

The clock is required for I2S playback with a bluetooth receiver (BT401).

I have tried using the internal MSI RC to generate the 12.288MHz clock for SAI,  but the BT401 is misbehaving so it might be because the MSI RC clock has too much jitter.

I was wondering if a ASFL1-12.288MHZ-EC-T would be suitable for the clock source for the SAI external clock input....

https://uk.rs-online.com/web/p/crystal-oscillators/2403583

Below is the setup... 

 

freeflyer_0-1766340884039.png

 

The I2S amplifier (MAX98357A) seems to work fine with the 12.288MHz clock generated by the internal MSI RC and PLL.

 

But the BT401 either requires multiple attempts to start playing and sometimes plays just a screeching sound for a few seconds then stops.  So I need to rule out whether the issue is caused by clock jitter by trying a more accurate clock source.

 

I am currently using the STM32L433 Nucleo board which has a footprint for an external HSE crystal, but I cannot find a crystal for that footpring with a 12.288MHz frequency.

 

The ASFL1-12.288MHZ-EC-T seems to be an all in one device, you just provide power and it generates the output clock.  So its not like a crystal which needs a special drive circuit ?

 

I have read the application note AN2867 Recommended resonators for STM32 MCUs/MPUs, but its complicated and just confused me.

    This topic has been closed for replies.

    7 replies

    Super User
    December 21, 2025

    Hi, 

    1. you again... :)

    2. ASFL1-12.288MHZ is a oscillator, yes, just needs 3v3 and it will output 12.xx MHz .

    3. You pic is bad/wrong: L433 master receive means: all arrows go from BT401 to the L433/SAI , as BT401 is "master" here, sending out BCK, LRCK , DAT .

    4. you need no extra clock then, because its coming from BT401 and you cannot change the clock to any other source.  

    5. > But the BT401 either requires multiple attempts to start playing 

    Problem could be anything...first: IS bt401 master ? check with a scope, what happens on its output BCK, LRCK , DAT . I dont know, how you /or the BT chips handle a not existing connection , until you connect and send data.

    So the problem might be: BT connection has to be stable and without dropouts, then output to dac should be fine.

    Until stable data stream from bt401 is established , you should mute the sound output, as it will be useless noise.

    freeflyerAuthor
    Graduate II
    December 21, 2025

    Hi AScha.3, yes me again :)

    I have got everything working nicely, other than the issue with the bluetooth receiver.

    When we last discussed this, I had the BT401 as a master I2S and the STM32 as a slave I2S.

    However, I had to swap this around because the BT401 I2S clocks were intermittent at powerup which meant the voice prompt (stored in external flash connected to the STM32 via SPI with DMA) which is called at power up stuttered.

    In fact its a better solution to use the STM32 as the I2S master, because it removes dependancy on the BT401 to generate the I2s clocks.  This means that the voice prompts (which are critical to the system) will work even if the BT401 fails for some reason.

    The STM32 outputs the bit clock and left/right clock to the BT401 and amplifier, the BT401 outputs data to the STM32 and the STM32 outputs data to the amplifier.

    Below is the SAI configuratoin which should align with the block diagram...

    freeflyer_0-1766345144358.png

     

    This is all working correctly, other than the issue with playing audio from the BT401.

    Super User
    December 21, 2025

    Hi,

    i dont know, how the BT audio doing this - you have to search/read : the problem : who is the master (of clock for play audio) ; see , its always same problem: as long as data is handled as "data" , in web or PC ...no problem; if data is "music" or audio, its still data. BUT if it comes to real world -analog- we have to convert, from digital to analog, and this demands the correct time, data is coming to analog. So the last in chain, the DAC , has to get the defined clock rate, 44k1 or 48k ..., and all the line down, where data is coming from, has to adjust to this, to "play" perfect.

    But in BT or PC there usually is a device, in PC called mixer, that decides to play ...48kHz . So all down the stream have to adjust to this. Or you can change the "master clock source" to ...the DAC , but this needs special adjustment in the transmission and devices...

    So : can the BT be slave (for the data rate)? and the master clock coming from the L433 ? check this.

    +

    Imagine simple problem, i got when playing MP3 from web: my device has its clock from a crystal, making 44k1 audio. The server somewhere on this planet has its own clock , also from a crystal, sending data for "44k1 rate" , when i order next packet...etc. BUT crystals have not infinite precision, so my crystal might be 1/100000 faster than the server's crystal. Nothing happens, just i want more data from the "future" - until the limit of some buffer setting in the server is reached, maybe after 2 h continuous stream playing. Now the server will denie more fast/future data, and i have to adjust the timing in some way. Usually just a "dropout", and it will go on until again times are drifted apart too much. Or you make some intelligent adjustment, like inserting samples from time to time, to sync the "time" to the server.

     

    freeflyerAuthor
    Graduate II
    December 23, 2025

    I have fitted the ASFL1-12.288MHZ-EC-T but the STM32 is no longer generating the I2S clocks (bit clock & left/right clock) so my I2S audio has completely stopped working :(

    The output of the ASFL1 is connected to pin PA0 of the STM32.

    In CubeMX I enabled SAI Extern clock...

    freeflyer_1-1766501921315.png

    The SAI clock is configured to use SAI EXT...

    freeflyer_0-1766501762268.png

     

    I have checked the 12.288MHz output on a scope....

     

    freeflyer_2-1766502115763.png

     

    For reference, below is the clock configuration when I2S did work (with the exception of the BT issues).  This is when I used the internal MSI RC to generate the 12.288MHz clock...

    freeflyer_3-1766502234883.png

     

     

    The only thing that has changed is the SAI clock source, instead of using the internal MSI RC it is using the external SAI pin.

    So why does it not work with the external SAI 12.288MHz clock ?

    freeflyerAuthor
    Graduate II
    December 23, 2025

    Is this a clue ?

    If so it makes no sense, because it implies that SAI_EXTCLK on pin PA0 is an output due to the fact the GPIO mode is push/pull....

     

    freeflyer_0-1766519977934.png

     

    So if its an output, how can it be used to clock the SAI peripheral ???

     

    Technical Moderator
    December 26, 2025

    Hello @freeflyer ,

    Regarding this statement:


    @freeflyer wrote:

    The ASFL1-12.288MHZ-EC-T seems to be an all in one device, you just provide power and it generates the output clock.  So its not like a crystal which needs a special drive circuit ?

    I have read the application note AN2867 Recommended resonators for STM32 MCUs/MPUs, but its complicated and just confused me.


    ASFL1-12.288MHZ-EC-T is a crystal oscillator (XO) according to its datasheet: while AN2867 is treating the case of crystals (XTAL) and resonators.

    In other hand, if AN2867 looks complicated, I suggest to refer to this article: How to select a compatible crystal and load capacitors for STM32 with layout guidelines, a simplified version of that application note ;)

    Visitor II
    December 26, 2025

    The MSI RC + PLL is fine for some codecs, but Bluetooth audio can be much more sensitive. An external low-jitter clock is the right thing to test. The ASFL1 you linked is an oscillator, not a crystal, so it doesn’t need a load network just power and proper routing to the SAI clock input. That makes it a good option for ruling out clock quality issues. Using the internal RC here can feel like a ruleta de la suerte online with BT audio, so a clean external clock should quickly confirm whether jitter is the root cause.

    freeflyerAuthor
    Graduate II
    December 26, 2025

    Yes I have already done this, I tried to feed the 12.288 MHz from the osillator into the SAI EXTCLOCK pin but it did not work.  So instead I fed it into the HSE pin and it worked, but I still had the same issues with the BT401 playback.  So I concluded that the issue is not due to clock drift/jitter of the MSI, because the issue still occurs when I use the oscillator

    Visitor II
    December 26, 2025

    The MSI RC + PLL is fine for some codecs, but Bluetooth audio can be much more sensitive. An external low-jitter clock is the right thing to test. The ASFL1 you linked is an oscillator, not a crystal, so it doesn’t need a load network just power and proper routing to the SAI clock input. That makes it a good option for ruling out clock quality issues. 

    freeflyerAuthor
    Graduate II
    December 27, 2025

    I found the reason why the SAI EXT CLOCK was not being configured.

    The generated code in the file stm32l4xx_hal_msp.c configures all the periperhal clocks.

    When initialising each peripheral, the clock selection is defined by PeriphClkInit.PeriphClockSelection.

    But for some reason, when initialising the SAI peripheral (HAL_SAI_MspIni) there is no value assigned to PeriphClkInit.PeriphClockSelection

    A value is assigned to PeriphClkInit.Sai1ClockSelection (RCC_SAI1CLKSOURCE_PIN) but because PeriphClkInit.PeriphClockSelection is zero the SAI clock peripheral never gets configured

    So I manually added the line (for SAI block B)... 

     

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;

     

    So is this a bug ?  All other periphals (e.g. USB, UART, I2C etc) are assigned with a value for PeriphClkInit.PeriphClockSelection with the exception of the SAI.

    HAL_SAI_MspIni is shown below (with my manually added line for block B)...

    void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
    {
    
     GPIO_InitTypeDef GPIO_InitStruct;
     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    /* SAI1 */
     if(hsai->Instance==SAI1_Block_A)
     {
     /* Peripheral clock enable */
    
     /** Initializes the peripherals clock
     */
     PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PIN;
     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (SAI1_client == 0)
     {
     __HAL_RCC_SAI1_CLK_ENABLE();
     }
     SAI1_client ++;
    
     /**SAI1_A_Block_A GPIO Configuration
     PB13 ------> SAI1_SCK_A
     PA9 ------> SAI1_FS_A
     PA10 ------> SAI1_SD_A
     */
     GPIO_InitStruct.Pin = BT_I2S_SCK_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
     HAL_GPIO_Init(BT_I2S_SCK_GPIO_Port, &GPIO_InitStruct);
    
     GPIO_InitStruct.Pin = BT_I2S_FS_Pin|BT_I2S_SD_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
     /* Peripheral DMA init*/
    
     hdma_sai1_a.Instance = DMA2_Channel1;
     hdma_sai1_a.Init.Request = DMA_REQUEST_1;
     hdma_sai1_a.Init.Direction = DMA_PERIPH_TO_MEMORY;
     hdma_sai1_a.Init.PeriphInc = DMA_PINC_DISABLE;
     hdma_sai1_a.Init.MemInc = DMA_MINC_ENABLE;
     hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
     hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
     hdma_sai1_a.Init.Mode = DMA_CIRCULAR;
     hdma_sai1_a.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     if (HAL_DMA_Init(&hdma_sai1_a) != HAL_OK)
     {
     Error_Handler();
     }
    
     /* Several peripheral DMA handle pointers point to the same DMA handle.
     Be aware that there is only one channel to perform all the requested DMAs. */
     __HAL_LINKDMA(hsai,hdmarx,hdma_sai1_a);
    
     __HAL_LINKDMA(hsai,hdmatx,hdma_sai1_a);
    
     }
     if(hsai->Instance==SAI1_Block_B)
     {
     /* Peripheral clock enable */
    
     /** Initializes the peripherals clock
     */
     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1; // MANUALLY ADDED 
     PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PIN;
     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
     {
     Error_Handler();
     }
    
     if (SAI1_client == 0)
     {
     __HAL_RCC_SAI1_CLK_ENABLE();
     }
     SAI1_client ++;
    
     /**SAI1_B_Block_B GPIO Configuration
     PA4 ------> SAI1_FS_B
     PB3 (JTDO-TRACESWO) ------> SAI1_SCK_B
     PB5 ------> SAI1_SD_B
     */
     GPIO_InitStruct.Pin = AMP_I2S_FS_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
     HAL_GPIO_Init(AMP_I2S_FS_GPIO_Port, &GPIO_InitStruct);
    
     GPIO_InitStruct.Pin = AMP_I2S_SCK_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
     HAL_GPIO_Init(AMP_I2S_SCK_GPIO_Port, &GPIO_InitStruct);
    
     GPIO_InitStruct.Pin = AMP_I2S_SD_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_PULLDOWN;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
     HAL_GPIO_Init(AMP_I2S_SD_GPIO_Port, &GPIO_InitStruct);
    
     /* Peripheral DMA init*/
    
     hdma_sai1_b.Instance = DMA2_Channel2;
     hdma_sai1_b.Init.Request = DMA_REQUEST_1;
     hdma_sai1_b.Init.Direction = DMA_MEMORY_TO_PERIPH;
     hdma_sai1_b.Init.PeriphInc = DMA_PINC_DISABLE;
     hdma_sai1_b.Init.MemInc = DMA_MINC_ENABLE;
     hdma_sai1_b.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
     hdma_sai1_b.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
     hdma_sai1_b.Init.Mode = DMA_CIRCULAR;
     hdma_sai1_b.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     if (HAL_DMA_Init(&hdma_sai1_b) != HAL_OK)
     {
     Error_Handler();
     }
    
     /* Several peripheral DMA handle pointers point to the same DMA handle.
     Be aware that there is only one channel to perform all the requested DMAs. */
     __HAL_LINKDMA(hsai,hdmarx,hdma_sai1_b);
     __HAL_LINKDMA(hsai,hdmatx,hdma_sai1_b);
     }
    }

     

    Visitor II
    December 28, 2025

    It sounds like you’re running into issues because the MSI RC clock inside the STM32L433 has too much jitter for your BT401. That can definitely cause the kind of problems you’re seeing, like screeching sounds or needing multiple tries to start playback.

    Yes, the ASFL1-12.288MHZ-EC-T should work for your setup. It’s a crystal oscillator with a built-in circuit, so you don’t need a separate drive circuit like a normal crystal. You just connect power and ground, and it gives a clean 12.288 MHz output, which should be much more stable than the internal MSI RC.

    Using it as the SAI external clock should help reduce jitter and may fix the BT401 playback issues. Make sure your connections are solid and keep the traces short if possible to avoid introducing extra noise.

    The main thing is that your MAX98357A amplifier might still work with the internal MSI clock because it’s more tolerant of jitter, but the BT401 seems to need a precise clock. Switching to the ASFL1 oscillator is a pinterest video downloader good next step.

    Hope this was helpful!