Getting 100 kHz out of an ESP32?

I found this code:

// Function generator Sin
// (C) Helmut Weber
//
// Provided as is as example
// Free for everyone
//
// 50 Hz - 200,000 Hz:     frequency error ~ 1%
// from 17 Hz - 250000   possible
 
 
// based on:
// https://github.com/krzychb/dac-cosine
 
// clk_8m_div and frequency_step are computed to give the best result for the wished frequency
 
 
 
/* 
 *  DAC Cosine Generator Example
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
 
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc.h"
 
 
#include "driver/dac.h"
 
/* Declare global sine waveform parameters
 * so they may be then accessed and changed from debugger
 * over an JTAG interface
 */
 
// Esp32 @ 240 MHz:
 
// f=125.6*step/(div+1)            [div=0..7] [calc: (div+1)]
 
// step0:
// 0=15.61Hz 1=--
 
// step 1:
// 0 = 125.6 Hz 1 = 62.50 Hz 2 = 41.67Hz 3=31.35Hz 4=25.00Hz 5=20.92Hz 6=17.86Hz 7=15.63Hz
 
// step 2:125,6
 
// 0= 250.0 Hz 1=125Hz 2=83.68 Hz 3=62.5 Hz 4=50.1 Hz 5=41.74Hz  6=35.74 Hz  7=31.35Hz
 
 // step 10
 // 0 = 1.248 kHz 1 = 625.4 Hz 2 = 417.4 Hz (noisy) 3 = 31.33 Hz 4 = 250.6  5 = 208.3 Hz  6=178.9 7=156.3
 
 // step 100:
 // 0: 12.53 kHz  1 = 6.266 kHz 2=4.173kHz 3= 3.127 kHz 4=2.505 kHz 6=1.789 kHz 7=1.565KHz
 
 
// step 500:
// 0: 62.54 kHz (noisy) 1 = 31.33 kHz 2 = 20.86 kHz  5 = 10.5 kHz   6 =20.88 KhZ  7=
 
// step 1000:
// 0 = 125 kHz, 1 = 62.11 kHz, 5 = 20.73 kHz    ==>>> 10 = 42.02 kHz 100
 
// step 2000
// 0: 249.4 kHz(unten verzerrt)  1 = 125.8 kHz (noisy)  5 = 41.5 kHz (noisy)
 
int clk_8m_div = 1;      // RTC 8M clock divider (division is by clk_8m_div+1, i.e. 0 means 8MHz frequency)
int frequency_step = 7;  // Frequency step for CW generator
int scale = 1;           // 50% of the full scale // scale 0 == fill scale = bad signal (no longer a sine wave)
int offset;              // leave it default / 0 = no any offset
int invert = 2;          // invert MSB to get sine waveform  // 3: invert 180°
 
 
/*
 * Enable cosine waveform generator on a DAC channel
 */
void dac_cosine_enable(dac_channel_t channel)
{
    // Enable tone generator common to both channels
    SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
    switch(channel) {
        case DAC_CHANNEL_1:
            // Enable / connect tone tone generator on / to this channel
            SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
            // Invert MSB, otherwise part of waveform will have inverted
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV1, 2, SENS_DAC_INV1_S);
            break;
        case DAC_CHANNEL_2:
            SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, 2, SENS_DAC_INV2_S);
            break;
        default :
           printf("Channel %d\n", channel);
    }
}
 
 
/*
 * Set frequency of internal CW generator common to both DAC channels
 *
 * clk_8m_div: 0b000 - 0b111
 * frequency_step: range 0x0001 - 0xFFFF
 *
 */
void dac_frequency_set(int clk_8m_div, int frequency_step)
{
    REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DIV_SEL, clk_8m_div);
    SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL1_REG, SENS_SW_FSTEP, frequency_step, SENS_SW_FSTEP_S);
}
 
 
/*
 * Scale output of a DAC channel using two bit pattern:
 *
 * - 00: no scale
 * - 01: scale to 1/2
 * - 10: scale to 1/4
 * - 11: scale to 1/8
 *
 */
void dac_scale_set(dac_channel_t channel, int scale)
{
    switch(channel) {
        case DAC_CHANNEL_1:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE1, scale, SENS_DAC_SCALE1_S);
            break;
        case DAC_CHANNEL_2:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_SCALE2, scale, SENS_DAC_SCALE2_S);
            break;
        default :
           printf("Channel %d\n", channel);
    }
}
 
 
/*
 * Offset output of a DAC channel
 *
 * Range 0x00 - 0xFF
 *
 */
void dac_offset_set(dac_channel_t channel, int offset)
{
    switch(channel) {
        case DAC_CHANNEL_1:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_DC1, offset, SENS_DAC_DC1_S);
            break;
        case DAC_CHANNEL_2:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_DC2, offset, SENS_DAC_DC2_S);
            break;
        default :
           printf("Channel %d\n", channel);
    }
}
 
 
/*
 * Invert output pattern of a DAC channel
 *
 * - 00: does not invert any bits,
 * - 01: inverts all bits,
 * - 10: inverts MSB,
 * - 11: inverts all bits except for MSB
 *
 */
void dac_invert_set(dac_channel_t channel, int invert)
{
    switch(channel) {
        case DAC_CHANNEL_1:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV1, invert, SENS_DAC_INV1_S);
            break;
        case DAC_CHANNEL_2:
            SET_PERI_REG_BITS(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_INV2, invert, SENS_DAC_INV2_S);
            break;
        default :
           printf("Channel %d\n", channel);
    }
}
 
/*
 * Main task that let you test CW parameters in action
 *
*/
void dactask(void* arg)
{
double f, f_target, delta, delta_min=9999999.0;
int step_target=0, divi_target=0;
 
  //From experiments:  f=125.6*step/(div+1)
 
    // this frequency is wanted:
    f_target=200000.0;                             // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
     
 
    // check all combinations of step iand divi to get the best guess:
    for (int step=1;step<2000; step++) {
      for (int divi=0; divi<8; divi++) {
        f=125.6*(double)step/(double)(divi+1);
        delta= abs((f_target-f));
        if (delta  < delta_min) {delta_min=delta; step_target=step; divi_target=divi; }
      }
    }
   
    clk_8m_div=divi_target;
    frequency_step=step_target;
   
    printf("divi=%d step=%d\n",divi_target, step_target);
    while(1){
 
        // frequency setting is common to both channels
        dac_frequency_set(clk_8m_div, frequency_step);
 
        /* Tune parameters of channel 2 only
         * to see and compare changes against channel 1
         */
        dac_scale_set(DAC_CHANNEL_2, scale);
        dac_offset_set(DAC_CHANNEL_2, offset);
        dac_invert_set(DAC_CHANNEL_2, invert);
 
        float frequency = RTC_FAST_CLK_FREQ_APPROX / (1 + clk_8m_div) * (float) frequency_step / 65536;
        printf("THEORIE:   clk_8m_div: %d, frequency step: %d, frequency: %.0f Hz\n", clk_8m_div, frequency_step, frequency);
        printf("PRACTICAL: frequency: %.0f Hz\n", 125.6*(float)frequency_step /(1 + (float)clk_8m_div) );
       
        printf("DAC2 scale: %d, offset %d, invert: %d\n", scale, offset, invert);
        vTaskDelay(2000/portTICK_PERIOD_MS);
    }
}

void setup()
{
    dac_cosine_enable(DAC_CHANNEL_1);
    dac_cosine_enable(DAC_CHANNEL_2);
 
    dac_output_enable(DAC_CHANNEL_1);
    dac_output_enable(DAC_CHANNEL_2);
 
    xTaskCreate(dactask, "dactask", 1024*3, NULL, 10, NULL);
}

void loop()
{}```


How is it used to create 100 kHz? Does xTaskCreate need to be changed? 
What pin does it output the signal?

Try changing that line to:

f_target=100000.0;

1 Like

oh, duh, thanks!

I'll re-read to find which pin it outputs on...

Probably DAC1 (GPIO25) or DAC2 (GPIO26)

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.