AFE Driver
Q: The v2.2.0 SDK AFE driver (afe.c) has interrupt handlers for the Command FIFO interrupt (AFE_CmdFIFO_Int_Handler) and the Data FIFO interrupt (AFE_DataFIFO_Int_Handler), but not for the Generate or Capture interrupts. Are there handlers available for the Generate and Capture interrupts?
A: The v2.3.X SDK is currently under development (at time of print, 11 Feb 2015). The AFE driver in this new revision of the SDK will handle Generate and Capture interrupts and will introduce a new function which can register a callback for any of the 4 AFE interrupts. Preliminary code for the Generate and Capture interrupts and the register callback function are below for reference ahead of the v2.3.X SDK release.
/* ANALOG_CAPTURE_INT handler */
ADI_INT_HANDLER(AFE_Capture_Int_Handler) {
/* Only 1 instance of the AFE in the system */
ADI_AFE_DEV_HANDLE hDevice = pAFE_DevData;
uint32_t sources;
uint32_t enables;
uint32_t clear = 0;
uint32_t disable = 0;
sources = hDevice->pAFE->AFE_ANALOG_CAPTURE_INT;
enables = hDevice->pAFE->AFE_ANALOG_CAPTURE_IEN;
/* Interrupt bit: ADC_RESULT_READY */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_ADC_RESULT_READY) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_RESULT_READY_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_CAPTURE_INT_ADC_RESULT_READY;
}
/* Interrupt bit: DFT_RESULT_READY */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_DFT_RESULT_READY) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_DFT_RESULT_READY_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_CAPTURE_INT_DFT_RESULT_READY;
}
/* Interrupt bit: SUPPLY_LPF_RESULT_READY */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_SUPPLY_LPF_RESULT_READY) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_SUPPLY_LPF_RESULT_READY_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_CAPTURE_INT_SUPPLY_LPF_RESULT_READY;
}
/* Interrupt bit: TEMP_RESULT_READY */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_TEMP_RESULT_READY) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_TEMP_RESULT_READY_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_CAPTURE_INT_TEMP_RESULT_READY;
}
/* Interrupt bit: ADC_MIN_FAIL */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_ADC_MIN_FAIL) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_MIN_FAIL_IEN)) {
/* Since this is typically an error condition, we don't care if there is one */
/* or multiple interrupts, so schedule interrupt to be disabled. */
disable |= BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_MIN_FAIL_IEN;
}
/* Interrupt bit: ADC_MAX_FAIL */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_ADC_MAX_FAIL) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_MAX_FAIL_IEN)) {
/* Since this is typically an error condition, we don't care if there is one */
/* or multiple interrupts, so schedule interrupt to be disabled. */
disable |= BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_MAX_FAIL_IEN;
}
/* Interrupt bit: ADC_DELTA_FAIL */
if ((sources & BITM_AFE_AFE_ANALOG_CAPTURE_INT_ADC_DELTA_FAIL) &&
(enables & BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_DELTA_FAIL_IEN)) {
/* Since this is typically an error condition, we don't care if there is one */
/* or multiple interrupts, so schedule interrupt to be disabled. */
disable |= BITM_AFE_AFE_ANALOG_CAPTURE_IEN_ADC_DELTA_FAIL_IEN;
}
/* Check if there is a callback defined */
if (hDevice->cbCaptureFcn) {
/* Call the function if the interrupt is watched */
/* Need to check both interrupts scheduled to be cleared */
/* and interrupts scheduled to be disabled to find out */
/* what interrupt caused this ISR to be entered */
if ((clear | disable) & hDevice->cbCaptureWatch) {
/* Passing to the callback the bits scheduled for clear or disable */
hDevice->cbCaptureFcn(hDevice, 0, NULL);
}
}
adi_AFE_EnableInterruptSource(hDevice, ADI_AFE_INT_GROUP_CAPTURE, disable, false);
adi_AFE_ClearInterruptSource(hDevice, ADI_AFE_INT_GROUP_CAPTURE, clear);
}
/* ANALOG_GEN_INT handler */
ADI_INT_HANDLER(AFE_Generate_Int_Handler) {
/* Only 1 instance of the AFE in the system */
ADI_AFE_DEV_HANDLE hDevice = pAFE_DevData;
uint32_t sources;
uint32_t enables;
uint32_t clear = 0;
sources = hDevice->pAFE->AFE_ANALOG_GEN_INT;
enables = hDevice->pAFE->AFE_ANALOG_GEN_IEN;
/* Interrupt bit: DELAY_COMMAND_DONE */
if ((sources & BITM_AFE_AFE_ANALOG_GEN_INT_DELAY_COMMAND_DONE) &&
(enables & BITM_AFE_AFE_ANALOG_GEN_IEN_DELAY_COMMAND_DONE_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_GEN_INT_DELAY_COMMAND_DONE;
}
/* Interrupt bit: HARDWARE_SETUP_DONE */
if ((sources & BITM_AFE_AFE_ANALOG_GEN_INT_HARDWARE_SETUP_DONE) &&
(enables & BITM_AFE_AFE_ANALOG_GEN_IEN_HARDWARE_SETUP_DONE_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_GEN_INT_HARDWARE_SETUP_DONE;
}
/* Interrupt bit: BREAK_SEQUENCE_ORG */
if ((sources & BITM_AFE_AFE_ANALOG_GEN_INT_BREAK_SEQUENCE_ORG) &&
(enables & BITM_AFE_AFE_ANALOG_GEN_IEN_BREAK_SEQUENCE_ORG_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_GEN_INT_BREAK_SEQUENCE_ORG;
}
/* Interrupt bit: CUSTOM_INT */
if ((sources & BITM_AFE_AFE_ANALOG_GEN_INT_CUSTOM_INT) &&
(enables & BITM_AFE_AFE_ANALOG_GEN_IEN_CUSTOM_INT_IEN)) {
/* Schedule interrupt to be cleared */
clear |= BITM_AFE_AFE_ANALOG_GEN_INT_CUSTOM_INT;
}
/* Check if there is a callback defined */
if (hDevice->cbGenerateFcn) {
/* Call the function if the interrupt is watched */
/* Need to check both interrupts scheduled to be cleared */
/* and interrupts scheduled to be disabled to find out */
/* what interrupt caused this ISR to be entered */
if (clear & hDevice->cbGenerateWatch) {
/* Passing to the callback the bits scheduled for clear or disable */
hDevice->cbGenerateFcn(hDevice, 0, NULL);
}
}
adi_AFE_ClearInterruptSource(hDevice, ADI_AFE_INT_GROUP_GENERATE, clear);
}
/*!
* @brief Application callback registration for AFE interrupt handlers.
*
* @param[in] hDevice Device handle obtained from adi_AFE_Init().
* @param[in] group AFE interrupt group type identifier.
* @param[in] cbFunc Application callback address; the function to call.
* @param[in] cbWatch The interrupts to watch, controlling which interrupts result in a callback.
*
* @return Status
* - #ADI_AFE_SUCCESS Call completed successfully.
* - #ADI_AFE_ERR_BAD_DEV_HANDLE Invalid device handle.
* - #ADI_AFE_ERR_NOT_INITIALIZED Device not initialized.
* - #ADI_AFE_ERR_ACLKOFF ACLK disabled from the clock gate.
* - #ADI_AFE_ERR_WRONG_ACLK_FREQUENCY Programmed ACLK frequency is not the required 16MHz.
* - #ADI_AFE_ERR_CALLBACK_OVERWRITE Attempt to overwrite existing callback.
*
* @details Registers an application-defined callback function with one of the AFE interrupt handlers.
* Callbacks are made in response to received AFE interrupts, depending on whether they are enabled
* and whether the corresponding callback watch bits are set. This allows the application to control which
* interrupts it wants to be called back on.
* The callback to the application is made in context of the originating interrupt (i.e. the AFE
* interrupt handler that is registered in the system's interrupt vector table). Extended processing
* during the callback (an extension of the AFE interrupt handler) is discouraged so as to avoid lower-priority
* interrupt blocking. Also, any register read-modify-write operations should be protected using the
* ADI_ENTER_CRITICAL_REGION()/ADI_EXIT_CRITICAL_REGION() pair to prevent higher-priority interrupts from modifying
* said register during the read-modify-write operation.
*
* @note CALLBACKS: AFE interrupt callbacks are \a disabled by default during the API initialization (#adi_AFE_Init()).
* The application may use the #adi_AFE_RegisterCallback() API to register an application-defined
* callback function with the interrupt handler that will be called in response to selected AFE interrupts.
* The callback registration API takes an interrupt mask (of type uint32_t) that designates the set of interrupts
* to watch (upon which to dispatch the callback). When any of the watched interrupts occur, the appropriate AFE
* interrupt handler will make the callback to the application for application-based interrupt handling. The application
* callback should \a avoid \a extended \a processing during the callback as the callback is made context of the initiating
* interrupt and will block lower-priority interrupts. If extended application-level interrupt processing is required, the
* application should schedule it for the main application loop and exit the callback as soon as possible.\n\n
*
*/
ADI_AFE_RESULT_TYPE adi_AFE_RegisterAfeCallback(ADI_AFE_DEV_HANDLE hDevice, ADI_AFE_INT_GROUP_TYPE group, ADI_CALLBACK cbFunc, uint32_t cbWatch) {
ADI_AFE_RESULT_TYPE result = ADI_AFE_SUCCESS;
#ifdef ADI_DEBUG
if (adi_AFE_InvalidHandle(hDevice)) {
return ADI_AFE_ERR_BAD_DEV_HANDLE;
}
if (adi_AFE_HandleNotInitialized(hDevice)) {
return ADI_AFE_ERR_NOT_INITIALIZED;
}
if (pADI_SYSCLK->CLKCON5 & BITM_SYSCLK_CLKCON5_ACLKOFF) {
return ADI_AFE_ERR_ACLKOFF;
}
if (16000000 != SystemGetClockFrequency(ADI_SYS_CLOCK_ACLK)) {
return ADI_AFE_ERR_WRONG_ACLK_FREQUENCY;
}
if (!((ADI_AFE_INT_GROUP_CAPTURE == group) || (ADI_AFE_INT_GROUP_GENERATE == group) || (ADI_AFE_INT_GROUP_CMD_FIFO == group) || (ADI_AFE_INT_GROUP_DATA_FIFO == group))) {
return ADI_AFE_ERR_INVALID_IRQ;
}
if ((cbFunc && hDevice->cbCaptureFcn) || (cbFunc && hDevice->cbGenerateFcn) || (cbFunc && hDevice->cbCmdFifoFcn) || (cbFunc && hDevice->cbDataFifoFcn)) {
return ADI_AFE_ERR_CALLBACK_OVERWRITE;
}
#endif
switch (group)
{
case ADI_AFE_INT_GROUP_CAPTURE:
hDevice->cbCaptureFcn = cbFunc;
hDevice->cbCaptureWatch = cbWatch;
break;
case ADI_AFE_INT_GROUP_GENERATE:
hDevice->cbGenerateFcn = cbFunc;
hDevice->cbGenerateWatch = cbWatch;
break;
case ADI_AFE_INT_GROUP_CMD_FIFO:
hDevice->cbCmdFifoFcn = cbFunc;
hDevice->cbCmdFifoWatch = cbWatch;
break;
case ADI_AFE_INT_GROUP_DATA_FIFO:
hDevice->cbDataFifoFcn = cbFunc;
hDevice->cbDataFifoWatch = cbWatch;
break;
}
return result;
}