andysworkshop/stm32plus

dac_circular example

Closed this issue · 5 comments

/*
 * This file is a part of the open source stm32plus library.
 * Copyright (c) 2011,2012,2013,2014 Andy Brown <www.andybrown.me.uk>
 * Please see website for licensing terms.
 */

#include "config/stm32plus.h"
#include "config/dac.h"

using namespace stm32plus;

/**
 * Demonstration of DAC channel 1 playing back a sampled waveform.
 *
 * Compatible MCU:
 *   STM32F0
 *
 */

// A sine wave centered around 2048
static uint16_t samples[] = { 2048, 2128, 2208, 2288, 2367, 2446, 2523,
    2599, 2674, 2748, 2820, 2890, 2958, 3023, 3087, 3148, 3206, 3261, 3314,
    3363, 3410, 3453, 3492, 3529, 3561, 3590, 3615, 3637, 3654, 3668, 3678,
    3684, 3686, 3684, 3678, 3668, 3654, 3637, 3615, 3590, 3561, 3529, 3492,
    3453, 3410, 3363, 3314, 3261, 3206, 3148, 3087, 3023, 2958, 2890, 2820,
    2748, 2674, 2599, 2523, 2446, 2367, 2288, 2208, 2128, 2048, 1967, 1887,
    1807, 1728, 1649, 1572, 1496, 1421, 1347, 1275, 1205, 1137, 1072, 1008, 947,
    889, 834, 781, 732, 685, 642, 603, 566, 534, 505, 480, 458, 441, 427, 417,
    411, 409, 411, 417, 427, 441, 458, 480, 505, 534, 566, 603, 642, 685, 732,
    781, 834, 889, 947, 1008, 1072, 1137, 1205, 1275, 1347, 1421, 1496, 1572,
    1649, 1728, 1807, 1887, 1967 };

enum {
  NUM_SAMPLES = sizeof(samples) / sizeof(samples[0])
};

class DacCircularTest {

public:
  void run() {

    Dac1<>::Parameters params;
    params.dac_trigger = DAC_Trigger_T6_TRGO; // Output only changes on trigger
    params.dac_waveGeneration = DAC_WaveGeneration_None;
    params.dac_outputBuffer = DAC_OutputBuffer_Enable;

    Dac1<DacChannel112BitLeftAlignmentFeature> dac(params);

    Dac1UpdateDmaChannel<Dac1UpdateDmaChannelInterruptFeature,
        DacDmaWriterFeature<DacChannel112BitRightAlignmentFeature,
        DMA_Priority_High, DMA_Mode_Circular> > dma;

    dma.DmaInterruptEventSender.insertSubscriber(
        DmaInterruptEventSourceSlot::bind(this, &DacCircular::onComplete));

    // Must enable all desired interrupts in one call
    dma.enableInterrupts(
        Dac1UpdateDmaChannelInterruptFeature::HALF_COMPLETE
            | Dac1UpdateDmaChannelInterruptFeature::COMPLETE);

    // Samples output on every second tick of the time base
    Timer6<Timer6InternalClockFeature, TimerUpdateMasterFeature> timer;
    timer.setTimeBaseByFrequency(NUM_SAMPLES * 440 * 2, 1, TIM_CounterMode_Up);
    timer.enableMasterFeature();

    dac.enablePeripheral();
    timer.enablePeripheral();

    dma.beginWrite(samples, NUM_SAMPLES);
  }

  /*
   * Subscriber callback is fired when the DMA transfer is (half)complete.
   * We could refresh the half that was just completed or just let it loop.s
   */
  void onComplete(DmaEventType det) {
    if (det == DmaEventType::EVENT_COMPLETE) {
      // refill second half of buffer (or just leave it alone)
    }
    if (det == DmaEventType::EVENT_HALF_COMPLETE) {
      // refill first half of buffer (or just leave it alone)
    }
  }
};

/*
 * Main entry point
 */

int main() {

  DacCircularTest test;
  test.run();

  // not reached
  return 0;
}

Looks like I forgot the infinite loop, but this is how the dac-circular feature can be used. In my project I'm playing back a compressed .au file. One thing I found unintuitive is that the counter seems to have to count from 0, 1 (overflow) which is 2x your output frequency.

Looks nice. Which MCUs is it compatible with?

Only testing with f051 so far but it probably works if you have a DAC
On Feb 13, 2016 4:14 AM, Andy Brown notifications@github.com wrote:Looks nice. Which MCUs is it compatible with?

—Reply to this email directly or view it on GitHub.

Example waveform capture from your example:

Wonderful
On Nov 12, 2016 09:39, Andy Brown notifications@github.com wrote:Example waveform capture from your example:

—You are receiving this because you authored the thread.Reply to this email directly, view it on GitHub, or mute the thread.