ASF4 Async DAC driver

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Noting here a couple of bugs / unexpected issues I've found with the DAC async driver as generated by Atmel START, on an ATSAM E54 (ATSAME54P20A).

 

The driver does not setup IRQ handlers for all the DAC interrupts. It only handles the first 2.

 

hpl_dac.c line 248

/**
 * \brief DMAC interrupt handler
 */
void DAC_0_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}
/**
 * \brief DMAC interrupt handler
 */
void DAC_1_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}

I expanded this to handle all 5 DAC interrupt handlers (as defined in startup_sam54.c line 460), other chips may have a differing number.

/**
 * \brief DMAC interrupt handler
 */
void DAC_0_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}
/**
 * \brief DMAC interrupt handler
 */
void DAC_1_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}
void DAC_2_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}
void DAC_3_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}
void DAC_4_Handler(void)
{
	_dac_interrupt_handler(_dac_dev);
}

I needed this because I was enabling both channels:

    dac_async_enable_channel(&DAC_0, 0);
    dac_async_enable_channel(&DAC_0, 1);

Enabling the second channel will call the EMPTY1 interrupt, which is handled by DAC_2_Handler. If this handler isn't setup the code will jump straight into the dummy handler. Note: The interrupt handler is _dac_interrupt_handler is designed to handle the _EMPTY1 interrupt, but isn't written to check for the DAC_INTFLAG_RESRDY0 or DAC_INTFLAG_RESRDY1 interrupts. If you want to use these you probably need to extend this function to handle those(?)

 

The next gotcha I found was that the dac_async_write_data would write to the DATABUF register. For this to then be acted upon requires the START0 or START1 input events to occur. I'm not sure how this event system works so can't advise on how to make these work. instead i changed _dac_async_write_data to match _dac_sync_write_data and write to the DATA register, which starts the conversion directly. The conversion complete interrupt still works as expected.


/**
 * \brief write synchronous DAC data for output
 */
void _dac_sync_write_data(struct _dac_sync_device *const device, const uint16_t data, const uint8_t ch)
{
	hri_dac_write_DATA_reg(device->hw, ch, data);
}

/**
 * \brief write DAC data for output
 */
void _dac_async_write_data(struct _dac_async_device *const device, const uint16_t data, const uint8_t ch)
{
	hri_dac_write_DATA_reg(device->hw, ch, data);
}

(Note that _dac_async_write is called from multiple places so I think it is best to update this function rather than the calls to it).

 

If anyone has any further advice or I've done something wrong, please point it out!

Last Edited: Mon. Jul 26, 2021 - 03:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That DATA vs DATBUF change was done here also, seems I had found it was documented to depend on the event (the async driver):

https://community.atmel.com/foru...

/Lars