This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Can I make one of the nRF5340 pins oscillate at 12.288MHz? (Audio PLL Clock)

I'm trying to avoid buying a 12.288MHz oscillator if I can make one of the pins on the nRF5340 oscillate at that frequency.

It looks like the ACLK is only available to the PDM and I2S peripherals.

Is there a way to make one or both of them use ACLK as its clock source and do a divide-by-1 so that the clock output will be 12.288MHz?

(The PDM or I2S interface doesn't need to "function" as a PDM or I2S peripheral.  It just needs to provide the 12.288MHz clock signal)

Parents
  • Hi,

     

    You can output the ACLK by setting the source to ACLK and .BYPASS=1 in this register:

    https://infocenter.nordicsemi.com/topic/ps_nrf5340/i2s.html?cp=3_0_0_6_14_9_26#register.CONFIG.CLKCONFIG

     

    You should then get the ACLK out on the selected MCLK pin. Note that some pins on the nRF5340-PDK are not routed to the pin header (used for other purposes). I took P0.10 for testing.

     

    Note that the ACLK and external HFCLK shall be started prior to enabling and starting the I2S peripheral:

     

    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    
    NRF_CLOCK->TASKS_HFCLKAUDIOSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKAUDIOSTARTED == 0);
    NRF_CLOCK->EVENTS_HFCLKAUDIOSTARTED = 0;

     

    Kind regards,

    Håkon

  • That worked.

    Here is the code that makes it work:

    #define I2S_MCK_PIN 7 // MCLK pin is P0.07
    
    #define I2S_DATA_BLOCK_WORDS 512 //How many numbers do we want. time reorded = DATA_BLOCK_WORDS / freq
    
    static u32_t m_buffer_rx32u[I2S_DATA_BLOCK_WORDS];
    static nrfx_i2s_buffers_t i2s_initial_buffers;
    
    
    
    // I2S ISR handler
    ISR_DIRECT_DECLARE(i2s_isr_handler)
    {
      nrfx_i2s_irq_handler();
      ISR_DIRECT_PM();  // PM done after servicing interrupt for best latency
      return 1;         // We should check if scheduling decision should be made
    }
    
    // I2S event handler
    static void i2s_data_handler(nrfx_i2s_buffers_t const *p_released, u32_t status)
    {
      if (NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED == status)
      {
        nrfx_i2s_next_buffers_set(&i2s_initial_buffers);
      }
    }
    
    /*****************************************************************************
    * Function: i2s_clk_init
    *
    * Description: provide 12.288MHz reference clock to audio ADC
    *
    * Parameters: none
    *
    * Returns: nothing
    *****************************************************************************/
    static void i2s_clk_init(void)
    {
      // the audio clock defaults to 12.288MHz, so we don't need to adjust it
    
      // configure I2S
      IRQ_DIRECT_CONNECT(I2S0_IRQn, 0, i2s_isr_handler, 0);
      i2s_initial_buffers.p_rx_buffer = m_buffer_rx32u;
    
      nrfx_i2s_config_t i2s_cfg = NRFX_I2S_DEFAULT_CONFIG(NRFX_I2S_PIN_NOT_USED, NRFX_I2S_PIN_NOT_USED, I2S_MCK_PIN, NRFX_I2S_PIN_NOT_USED, NRFX_I2S_PIN_NOT_USED);
      i2s_cfg.clksrc = NRF_I2S_CLKSRC_ACLK; // audio clock
      i2s_cfg.enable_bypass = true;         // bypass division, so we get the raw audio clock
      nrfx_err_t err_code = nrfx_i2s_init(&i2s_cfg, i2s_data_handler);
    
      if(err_code != NRFX_SUCCESS) 
      {
        printf("Error initializing I2S\n");
        return;
      }
    
      // start i2s
      err_code = nrfx_i2s_start(&i2s_initial_buffers, I2S_DATA_BLOCK_WORDS, 0);
      if (err_code != NRFX_SUCCESS)
      {
        printf("I2S start error\n");
      }
    }
    

Reply
  • That worked.

    Here is the code that makes it work:

    #define I2S_MCK_PIN 7 // MCLK pin is P0.07
    
    #define I2S_DATA_BLOCK_WORDS 512 //How many numbers do we want. time reorded = DATA_BLOCK_WORDS / freq
    
    static u32_t m_buffer_rx32u[I2S_DATA_BLOCK_WORDS];
    static nrfx_i2s_buffers_t i2s_initial_buffers;
    
    
    
    // I2S ISR handler
    ISR_DIRECT_DECLARE(i2s_isr_handler)
    {
      nrfx_i2s_irq_handler();
      ISR_DIRECT_PM();  // PM done after servicing interrupt for best latency
      return 1;         // We should check if scheduling decision should be made
    }
    
    // I2S event handler
    static void i2s_data_handler(nrfx_i2s_buffers_t const *p_released, u32_t status)
    {
      if (NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED == status)
      {
        nrfx_i2s_next_buffers_set(&i2s_initial_buffers);
      }
    }
    
    /*****************************************************************************
    * Function: i2s_clk_init
    *
    * Description: provide 12.288MHz reference clock to audio ADC
    *
    * Parameters: none
    *
    * Returns: nothing
    *****************************************************************************/
    static void i2s_clk_init(void)
    {
      // the audio clock defaults to 12.288MHz, so we don't need to adjust it
    
      // configure I2S
      IRQ_DIRECT_CONNECT(I2S0_IRQn, 0, i2s_isr_handler, 0);
      i2s_initial_buffers.p_rx_buffer = m_buffer_rx32u;
    
      nrfx_i2s_config_t i2s_cfg = NRFX_I2S_DEFAULT_CONFIG(NRFX_I2S_PIN_NOT_USED, NRFX_I2S_PIN_NOT_USED, I2S_MCK_PIN, NRFX_I2S_PIN_NOT_USED, NRFX_I2S_PIN_NOT_USED);
      i2s_cfg.clksrc = NRF_I2S_CLKSRC_ACLK; // audio clock
      i2s_cfg.enable_bypass = true;         // bypass division, so we get the raw audio clock
      nrfx_err_t err_code = nrfx_i2s_init(&i2s_cfg, i2s_data_handler);
    
      if(err_code != NRFX_SUCCESS) 
      {
        printf("Error initializing I2S\n");
        return;
      }
    
      // start i2s
      err_code = nrfx_i2s_start(&i2s_initial_buffers, I2S_DATA_BLOCK_WORDS, 0);
      if (err_code != NRFX_SUCCESS)
      {
        printf("I2S start error\n");
      }
    }
    

Children
Related