Microchip® Advanced Software Framework

Quick Start Guide for DAC - Callback

In this use case, the DAC will convert 16 samples using interrupt driven conversion.

When all samples have been sampled, a callback will be called that signals the main application that conversion is compete.

The DAC will be set up as follows:

  • Analog VCC as reference
  • Internal output disabled
  • Drive the DAC output to the VOUT pin
  • Right adjust data
  • The output buffer is disabled when the chip enters STANDBY sleep mode
  • DAC conversion is started with RTC overflow event

Setup

Prerequisites

There are no special setup requirements for this use case.

Code

Add to the main application source file, outside of any functions:

#define DATA_LENGTH (16)
struct rtc_module rtc_instance;
struct events_resource event_dac;
static volatile bool transfer_is_done = false;
static uint16_t dac_data[DATA_LENGTH];

Callback function:

void dac_callback(uint8_t channel)
{
UNUSED(channel);
transfer_is_done = true;
}

Copy-paste the following setup code to your user application:

{
struct rtc_count_events rtc_event;
struct rtc_count_config config_rtc_count;
rtc_count_get_config_defaults(&config_rtc_count);
config_rtc_count.prescaler = RTC_COUNT_PRESCALER_DIV_1;
config_rtc_count.mode = RTC_COUNT_MODE_16BIT;
#ifdef FEATURE_RTC_CONTINUOUSLY_UPDATED
config_rtc_count.continuously_update = true;
#endif
rtc_count_init(&rtc_instance, RTC, &config_rtc_count);
rtc_event.generate_event_on_overflow = true;
}
void configure_dac(void)
{
struct dac_config config_dac;
#if (SAML21)
dac_instance.start_on_event[DAC_CHANNEL_0] = true;
#else
dac_instance.start_on_event = true;
#endif
dac_init(&dac_instance, DAC, &config_dac);
struct dac_events events =
#if (SAML21)
{ .on_event_chan0_start_conversion = true };
#else
{ .on_event_start_conversion = true };
#endif
}

Define a data length variables and add to user application (typically the start of main()):

uint32_t i;

Add to user application initialization (typically the start of main()):

Workflow

  1. Create a module software instance structure for the DAC module to store the DAC driver state while in use.
    Note
    This should never go out of scope as long as the module is in use. In most cases, this should be global.
  2. RTC module is used as the event trigger for DAC in this case, create a module software instance structure for the RTC module to store the RTC driver state.
    struct rtc_module rtc_instance;
    Note
    This should never go out of scope as long as the module is in use. In most cases, this should be global.
  3. Create a buffer for the DAC samples to be converted by the driver.
    static uint16_t dac_data[DATA_LENGTH];
  4. Create a callback function that will be called when DAC completes convert job.
    void dac_callback(uint8_t channel)
    {
    UNUSED(channel);
    transfer_is_done = true;
    }
  5. Configure the DAC module.
    1. Create a DAC module configuration struct, which can be filled out to adjust the configuration of a physical DAC peripheral.
      struct dac_config config_dac;
    2. Initialize the DAC configuration struct with the module's default values.
      Note
      This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
    3. Configure the DAC module with starting conversion on event.
      #if (SAML21)
      dac_instance.start_on_event[DAC_CHANNEL_0] = true;
      #else
      dac_instance.start_on_event = true;
      #endif
    4. Initialize the DAC module.
      dac_init(&dac_instance, DAC, &config_dac);
    5. Enable DAC start on conversion mode.
      struct dac_events events =
      #if (SAML21)
      { .on_event_chan0_start_conversion = true };
      #else
      { .on_event_start_conversion = true };
      #endif
    6. Enable DAC event.
  6. Configure the DAC channel.
    1. Create a DAC channel configuration struct, which can be filled out to adjust the configuration of a physical DAC output channel.
      struct dac_chan_config config_dac_chan;
    2. Initialize the DAC channel configuration struct with the module's default values.
      dac_chan_get_config_defaults(&config_dac_chan);
      Note
      This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
    3. Configure the DAC channel with the desired channel settings.
    4. Enable the DAC channel so that it can output a voltage.
  7. Enable DAC module.
  8. Configure the RTC module.
    1. Create an RTC module event struct, which can be filled out to adjust the configuration of a physical RTC peripheral.
      struct rtc_count_events rtc_event;
    2. Create an RTC module configuration struct, which can be filled out to adjust the configuration of a physical RTC peripheral.
      struct rtc_count_config config_rtc_count;
    3. Initialize the RTC configuration struct with the module's default values.
      rtc_count_get_config_defaults(&config_rtc_count);
      Note
      This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
    4. Change the RTC module configuration to suit the application.
      config_rtc_count.prescaler = RTC_COUNT_PRESCALER_DIV_1;
      config_rtc_count.mode = RTC_COUNT_MODE_16BIT;
      #ifdef FEATURE_RTC_CONTINUOUSLY_UPDATED
      config_rtc_count.continuously_update = true;
      #endif
    5. Initialize the RTC module.
      rtc_count_init(&rtc_instance, RTC, &config_rtc_count);
    6. Configure the RTC module with overflow event.
      rtc_event.generate_event_on_overflow = true;
    7. Enable RTC module overflow event.
    8. Enable RTC module.
  9. Configure the Event resource.
    1. Create an event resource config struct, which can be filled out to adjust the configuration of a physical event peripheral.
      struct events_config event_config;
    2. Initialize the event configuration struct with the module's default values.
      events_get_config_defaults(&event_config);
      Note
      This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
    3. Change the event module configuration to suit the application.
      event_config.generator = EVSYS_ID_GEN_RTC_OVF;
      event_config.edge_detect = EVENTS_EDGE_DETECT_RISING;
      event_config.path = EVENTS_PATH_ASYNCHRONOUS;
      event_config.clock_source = GCLK_GENERATOR_0;
    4. Allocate the event resource.
      events_allocate(&event_dac, &event_config);
    5. Attach the event resource with user DAC start.
      #if (SAML21)
      events_attach_user(&event_dac, EVSYS_ID_USER_DAC_START_0);
      #else
      events_attach_user(&event_dac, EVSYS_ID_USER_DAC_START);
      #endif
  10. Register and enable the DAC Write Buffer Complete callback handler.
    1. Register the user-provided Write Buffer Complete callback function with the driver, so that it will be run when an asynchronous buffer write job completes.
    2. Enable the Read Buffer Complete callback so that it will generate callbacks.

Use Case

Code

Copy-paste the following code to your user application:

dac_data, DATA_LENGTH);
while (!transfer_is_done) {
/* Wait for transfer done */
}
while (1) {
}

Workflow

  1. Start a DAC conversion and generate a callback when complete.
  2. Wait until the conversion is complete.
    while (!transfer_is_done) {
    /* Wait for transfer done */
    }
  3. Enter an infinite loop once the conversion is complete.
    while (1) {
    }