/** * \brief Enable the DAC module. * * Enables the DAC interface and the selected output. If any internal reference * is selected it will be enabled. * * \param[in] module_inst Pointer to the DAC software instance struct * */ void dac_enable( struct dac_module *const module_inst) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; /* Enable selected output */ dac_module->CTRLB.reg |= module_inst->output; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } /* Enable the module */ dac_module->CTRLA.reg |= DAC_CTRLA_ENABLE; /* Enable internal bandgap reference if selected in the configuration */ if (module_inst->reference == DAC_REFERENCE_INT1V) { #if (SAMC21) system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_OUTPUT); } if(dac_module->CTRLA.reg & DAC_CTRLA_ENABLE) { while(! (dac_module->STATUS.reg & DAC_STATUS_READY)) { }; } #else system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP); }
/** * \brief Write to the DAC. * * This function writes to the DATA or DATABUF register. * If the conversion is not event-triggered, the data will be written to * the DATA register and the conversion will start. * If the conversion is event-triggered, the data will be written to DATABUF * and transferred to the DATA register and converted when a Start Conversion * Event is issued. * Conversion data must be right or left adjusted according to configuration * settings. * \note To be event triggered, the enable_start_on_event must be * enabled in the configuration. * * \param[in] module_inst Pointer to the DAC software device struct * \param[in] channel DAC channel to write to * \param[in] data Conversion data * * \return Status of the operation. * \retval STATUS_OK If the data was written */ enum status_code dac_chan_write( struct dac_module *const module_inst, enum dac_channel channel, const uint16_t data) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } if (module_inst->start_on_event[channel]) { /* Write the new value to the buffered DAC data register */ dac_module->DATABUF[channel].reg = data; } else { /* Write the new value to the DAC data register */ dac_module->DATA[channel].reg = data; } return STATUS_OK; }
/** * \brief Enable the DAC module. * * Enables the DAC interface and the selected output. If any internal reference * is selected it will be enabled. * * \param[in] module_inst Pointer to the DAC software instance struct * */ void dac_enable( struct dac_module *const module_inst) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } /* Enable the module */ dac_module->CTRLA.reg |= DAC_CTRLA_ENABLE; /* Enable internal bandgap reference if selected in the configuration */ if (module_inst->reference == DAC_REFERENCE_INTREF) { system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_OUTPUT); } if(dac_module->DACCTRL[DAC_CHANNEL_0].reg & DAC_DACCTRL_ENABLE) { while(! (dac_module->STATUS.reg & DAC_STATUS_READY(DAC_CHANNEL_0 + 1))) { }; } else if(dac_module->DACCTRL[DAC_CHANNEL_1].reg & DAC_DACCTRL_ENABLE) { while(! (dac_module->STATUS.reg & DAC_STATUS_READY(DAC_CHANNEL_1 + 1))) { }; } }
/** * \brief Write to the DAC. * * This function converts a specific number of digital data. * The conversion should be event-triggered, the data will be written to DATABUF * and transferred to the DATA register and converted when a Start Conversion * Event is issued. * Conversion data must be right or left adjusted according to configuration * settings. * \note To be event triggered, the enable_start_on_event must be * enabled in the configuration. * * \param[in] module_inst Pointer to the DAC software device struct * \param[in] channel DAC channel to write to * \param[in] buffer Pointer to the digital data write buffer to be converted * \param[in] length Length of the write buffer * * \return Status of the operation. * \retval STATUS_OK If the data was written or no data conversion required * \retval STATUS_ERR_UNSUPPORTED_DEV The DAC is not configured as using * event trigger * \retval STATUS_BUSY The DAC is busy to convert */ enum status_code dac_chan_write_buffer_wait( struct dac_module *const module_inst, enum dac_channel channel, uint16_t *buffer, uint32_t length) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } /* Zero length request */ if (length == 0) { /* No data to be converted */ return STATUS_OK; } #if DAC_CALLBACK_MODE == true /* Check if busy */ if (module_inst->job_status[channel] == STATUS_BUSY) { return STATUS_BUSY; } #endif /* Only support event triggered conversion */ if (module_inst->start_on_event[channel] == false) { return STATUS_ERR_UNSUPPORTED_DEV; } /* Blocks while buffer is being transferred */ while (length--) { /* Convert one data */ dac_chan_write(module_inst, channel, buffer[length]); /* Wait until Transmit is complete or timeout */ for (uint32_t i = 0; i <= DAC_TIMEOUT; i++) { if(channel == DAC_CHANNEL_0) { if (dac_module->INTFLAG.reg & DAC_INTFLAG_EMPTY0) { break; } else if (i == DAC_TIMEOUT) { return STATUS_ERR_TIMEOUT; } } else if(channel == DAC_CHANNEL_1) { if (dac_module->INTFLAG.reg & DAC_INTFLAG_EMPTY1) { break; } else if (i == DAC_TIMEOUT) { return STATUS_ERR_TIMEOUT; } } } } return STATUS_OK; }
/** * \internal Writes a DAC configuration to the hardware module. * * Writes out a given configuration to the hardware module. * * \param[out] module_inst Pointer to the DAC software instance struct * \param[in] config Pointer to the configuration struct * */ static void _dac_set_config( struct dac_module *const module_inst, struct dac_config *const config) { /* Sanity check arguments */ Assert(module_inst); Assert(config); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; /* Set selected DAC output to be enabled when enabling the module */ module_inst->output = config->output; module_inst->start_on_event = false; uint32_t new_ctrla = 0; uint32_t new_ctrlb = 0; /* Enable DAC in standby sleep mode if configured */ if (config->run_in_standby) { new_ctrla |= DAC_CTRLA_RUNSTDBY; } /* Set reference voltage */ new_ctrlb |= config->reference; /* Left adjust data if configured */ if (config->left_adjust) { new_ctrlb |= DAC_CTRLB_LEFTADJ; } #ifdef FEATURE_DAC_DATABUF_WRITE_PROTECTION /* Bypass DATABUF write protection if configured */ if (config->databuf_protection_bypass) { new_ctrlb |= DAC_CTRLB_BDWP; } #endif /* Voltage pump disable if configured */ if (config->voltage_pump_disable) { new_ctrlb |= DAC_CTRLB_VPD; } /* Apply the new configuration to the hardware module */ dac_module->CTRLA.reg = new_ctrla; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } dac_module->CTRLB.reg = new_ctrlb; }
/** * \brief Resets the DAC module. * * This function will reset the DAC module to its power on default values and * disable it. * * \param[in] module_inst Pointer to the DAC software instance struct */ void dac_reset( struct dac_module *const module_inst) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } /* Software reset the module */ dac_module->CTRLA.reg |= DAC_CTRLA_SWRST; }
/** * \brief Disable the DAC module. * * Disables the DAC interface and the output buffer. * * \param[in] module_inst Pointer to the DAC software instance struct * */ void dac_disable( struct dac_module *const module_inst) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Dac *const dac_module = module_inst->hw; while (dac_is_syncing(module_inst)) { /* Wait until the synchronization is complete */ } /* Disable DAC */ dac_module->CTRLA.reg &= ~DAC_CTRLA_ENABLE; }
/** * \brief Convert a specific number digital data to analog through DAC. * * This function will perform a conversion of specific number of digital data. * The conversion should be event-triggered, the data will be written to DATABUF * and transferred to the DATA register and converted when a Start Conversion * Event is issued. * Conversion data must be right or left adjusted according to configuration * settings. * \note To be event triggered, the enable_start_on_event must be * enabled in the configuration. * * \param[in] module_inst Pointer to the DAC software device struct * \param[in] channel DAC channel to write to * \param[in] buffer Pointer to the digital data write buffer to be converted * \param[in] length Size of the write buffer * * \return Status of the operation. * \retval STATUS_OK If the data was written * \retval STATUS_ERR_UNSUPPORTED_DEV If a callback that requires event driven * mode was specified with a DAC instance * configured in non-event mode * \retval STATUS_BUSY The DAC is busy to accept new job */ enum status_code dac_chan_write_buffer_job( struct dac_module *const module_inst, const enum dac_channel channel, uint16_t *buffer, uint32_t length) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Assert(buffer); UNUSED(channel); Dac *const dac_module = module_inst->hw; /* DAC interrupts require it to be driven by events to work, fail if in * unbuffered (polled) mode */ if (module_inst->start_on_event == false) { return STATUS_ERR_UNSUPPORTED_DEV; } if(module_inst->remaining_conversions != 0 || module_inst->job_status == STATUS_BUSY){ return STATUS_BUSY; } /* Wait until the synchronization is complete */ while (dac_is_syncing(module_inst)) { }; module_inst->job_status = STATUS_BUSY; module_inst->remaining_conversions = length; module_inst->job_buffer = buffer; module_inst->transferred_conversions = 0; /* Enable interrupt */ system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_DAC); dac_module->INTFLAG.reg = DAC_INTFLAG_UNDERRUN | DAC_INTFLAG_EMPTY; dac_module->INTENSET.reg = DAC_INTENSET_UNDERRUN | DAC_INTENSET_EMPTY; return STATUS_OK; }