MTB CAT1 Peripheral driver library
SAR (Successive-Approximation Register Analogue to Digital Converter)

General Description

This driver provides API functions to configure the SAR ADC subsystem within High Power Programmable Analog Sub-System.

HPPASS SAR key features:

The internal structure of the HPPASS SAR ADC is shown below.

hppass_sar.png

HPPASS SAR consists of SAR Sequencer, samplers, SAR ADC core and post-processing blocks. There are two types of samplers: direct and muxed. First 12 samplers are direct samplers, each connected to its own dedicated analog input, forming first 12 SAR channels. Last 4 samplers are muxed samplers, each can be connected to one of 4 shared analog inputs through the analog multiplexer, forming last 16 SAR channels. Although HPPASS supports 28 SAR channels in total, some channels may not be available on certain devices or be reserved. Refer to the device datasheet and reference manual for HPPASS SAR analog input pins mapping.

Note
When a muxed sampler is used, the analog multiplexer reconfiguration requires additional sample time. Refer to the device datasheet for details.

SAR Sequencer

The internal structure of the HPPASS SAR sequencer is shown below.

hppass_sar_sequencer.png

Operation of the SAR sequencer is controlled by the cy_stc_hppass_sar_grp_t configuration structures. HPPASS supports up to 8 SAR sequencer groups, each group can be configured to perform measurements on any combination of direct and muxed samplers with selected input trigger, sample time and priority.

In SAR sequencer group, direct samplers can be enabled by setting corresponding bit in cy_stc_hppass_sar_grp_t::dirSampMsk field, while muxed samplers are enabled by setting cy_stc_hppass_sar_grp_t::muxSampMsk field.

The SAR sequencer group can be triggered by HPPASS Input Trigger or AC (cy_stc_hppass_sar_grp_t::trig). To trigger selected group from the firmware, set cy_stc_hppass_sar_grp_t::trig to one of 8 HPPASS input triggers (cy_en_hppass_sar_trig_t) and configure selected input trigger in firmware mode by setting cy_stc_hppass_sar_grp_t::trig to CY_HPPASS_TR_FW_PULSE or CY_HPPASS_TR_FW_LEVEL. To start the group conversion, call Cy_HPPASS_SetFwTrigger function with the same trigger in the mask parameter.

The SAR sequencer group can perform immediate input sampling or include addition sample time for all enabled samplers. HPPASS SAR supports 3 different sample time settings, which are configured in cy_stc_hppass_sar_t::sampTime and selected for each SAR sequencer group in cy_stc_hppass_sar_grp_t::sampTime field.

SAR sequencer group can be configured to be put in high or low priority conversion queue. High-priority groups are always converted before low-priority groups and are guaranteed to be converted before sampler leakage renders the sample invalid. However, low-priority groups may be in the hold state for too long. Check the Cy_HPPASS_SAR_GetHoldViolationStatus function status to ensure that low-priority groups were converted before they expired.

Additionally, the SAR sequencer group can be configured in Continuous mode, where the group is retriggered automatically after the previous conversion is complete. This mode is configured in cy_stc_hppass_sar_grp_t::continuous field. In Continuous mode, the group can be stopped by calling Cy_HPPASS_SAR_DisableGroupContConvert function.

HW Initialization and Enable

Configuration snippet for one shot SAR application. Startup SAR state enables SAR. One shot SAR measurement state triggers SAR to perform one measurement.

#define CY_HPPASS_STARTUP_STT_NUM_ENTRIES (1U)
#define CY_HPPASS_MEASURE_STT_NUM_ENTRIES (1U)
#define CY_HPPASS_SAR_GROUP_TRIG (0x01U)
/* Startup SAR STT */
const cy_stc_hppass_ac_stt_t startupSTT =
{
.branchStateIdx = 0U,
.interrupt = false,
.count = 0U,
.gpioOutUnlock = false,
.gpioOutMsk = 0U,
.csgUnlock = {false, false, false, false, false},
.csgEnable = {false, false, false, false, false},
.csgDacTrig = {false, false, false, false, false},
.sarUnlock = true,
.sarEnable = true,
.sarGrpMsk = 0U,
.sarMux = {{0}, {0}, {0}, {0}}
};
/* One shot SAR measurement STT */
const cy_stc_hppass_ac_stt_t measureSTT =
{
.branchStateIdx = 0U,
.interrupt = false,
.count = 0U,
.gpioOutUnlock = false,
.gpioOutMsk = 0U,
.csgUnlock = {false, false, false, false, false},
.csgEnable = {false, false, false, false, false},
.csgDacTrig = {false, false, false, false, false},
.sarUnlock = false,
.sarEnable = false,
.sarGrpMsk = CY_HPPASS_SAR_GROUP_TRIG,
.sarMux = {{0}, {0}, {0}, {0}}
};
{
.muxChanIdx = {0, 0, 0, 0},
.priority = false,
.continuous = false
};
{
.diff = false,
.sign = false,
.result = true,
};
{
.lowSupply = false,
.offsetCal = false,
.linearCal = false,
.gainCal = false,
.chanId = false,
.dirSampEnMsk = CY_HPPASS_SAR_DIRECT_SAMP_0,
.holdCount = 29, /* Optimal value */
.aroute = true,
.muxSampGain = {CY_HPPASS_SAR_SAMP_GAIN_1, CY_HPPASS_SAR_SAMP_GAIN_1, CY_HPPASS_SAR_SAMP_GAIN_1, CY_HPPASS_SAR_SAMP_GAIN_1},
.sampTime = {100, 31, 31}, /* Optimal value */
.chan = {&chanCfg, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &chanCfg, NULL,
NULL, NULL, &chanCfg, NULL, NULL, NULL, &chanCfg, NULL, NULL, NULL, &chanCfg, NULL, NULL, NULL},
.grp = {&grpCfg, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
.limit = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
.muxMode = {CY_HPPASS_SAR_MUX_SEQ, CY_HPPASS_SAR_MUX_SEQ, CY_HPPASS_SAR_MUX_SEQ, CY_HPPASS_SAR_MUX_SEQ},
.fir = {NULL, NULL},
.fifo = NULL
};
/* HPPASS and AC state transition table configuration, used by Cy_HPPASS_Init API */
{
.ac =
{
.sttEntriesNum = CY_HPPASS_STARTUP_STT_NUM_ENTRIES,
.stt = &startupSTT,
.gpioOutEnMsk = 0U,
.startupClkDiv = 7U,
.startup =
{
{
.count = 0U,
.sar = true,
.csgChan = false,
.csgSlice = false,
.csgReady = false
},
{0},
{0},
{0}
}
},
.vref = CY_HPPASS_VREF_LOCAL,
.csg = NULL,
.sar = &sarCfg,
.trigIn = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}},
.trigLevel = {{0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}}
};

Functional snippet Application flow:

int main(void)
{
/* Set up internal routing, pins, and clock-to-peripheral connections */
init_cycfg_all();
Cy_SCB_UART_Init(UART_HW, &UART_config, &UART_context);
printf("Very basic HPPASS SAR Test Application Main...\r\n");
Cy_GPIO_Write(LED_RED_PORT, LED_RED_PIN, 0);
/* Initialize HPPASS */
if (CY_HPPASS_SUCCESS != Cy_HPPASS_Init(&cfg))
{
printf("Cy_HPPASS_Init returns error\r\n");
}
/* enable interrupts */
__enable_irq();
/* Set interrupt mask for Result Group 0 */
if (CY_HPPASS_SUCCESS != Cy_HPPASS_AC_Start(0U, 0U))
{
printf("Cy_HPPASS_AC_Start returns error\r\n");
}
printf("Waiting for SAR ready... \r\n");
printf("Update STT to make one SAR measurement\r\n");
if (CY_HPPASS_SUCCESS != Cy_HPPASS_AC_UpdateStateTransitionTable(CY_HPPASS_MEASURE_STT_NUM_ENTRIES, &measureSTT, 0U))
{
printf("Cy_HPPASS_AC_UpdateStateTransitionTable returns error\r\n");
}
if (CY_HPPASS_SUCCESS != Cy_HPPASS_AC_Start(0U, 0U))
{
printf("Cy_HPPASS_AC_Start returns error\r\n");
}
printf("Call one SAR measurement in loop and print the result\r\n");
printf("Start infinite loop...\r\n");
for (;;)
{
/* Polling SAR interrupt status register */
{
/* Clear interrupt for Result Group 0 */
Cy_GPIO_Inv(LED_RED_PORT, LED_RED_PIN);
/* Read channel 0 measurement result */
printf("SAR0 Result: %x ", Cy_HPPASS_SAR_Result_ChannelRead(0));
printf("SAR12 Result: %x ", Cy_HPPASS_SAR_Result_ChannelRead(12));
printf("SAR16 Result: %x ", Cy_HPPASS_SAR_Result_ChannelRead(16));
printf("SAR20 Result: %x ", Cy_HPPASS_SAR_Result_ChannelRead(20));
printf("SAR24 Result: %x\r\n", Cy_HPPASS_SAR_Result_ChannelRead(24));
if (CY_HPPASS_SUCCESS != Cy_HPPASS_AC_Start(0U, 0U))
{
printf("Cy_HPPASS_AC_Start returns error\r\n");
}
}
}
}

Interrupt Configuration and Initialization

To configure the SAR Group or Results interrupts in addition to the SAR and AC configuration tables, as shown in the snippet above, declare your own interrupt configuration structure for each interrupt source, for example:

const cy_stc_sysint_t sarGroup0Intr =
{
.intrSrc = pass_interrupt_sar_entry_done_0_IRQn,
.intrPriority = 0x02
};
const cy_stc_sysint_t sarResultsIntr =
{
.intrSrc = pass_interrupt_sar_results_IRQn,
.intrPriority = 0x03
};

and initialize those configurations in the executable code. That code can be designed as a separate function (see the snippet below):

/* Initialize SAR and AC interrupts in HPPASS */
static void My_HPPASS_Interrupt_Config()
{
/* Initialize interrupt channels */
Cy_SysInt_Init(&sarGroup0Intr, Cy_HPPASS_SAR_Group0_Isr);
Cy_SysInt_Init(&sarResultsIntr, Cy_HPPASS_SAR_Results_Isr);
Cy_SysInt_Init(&sarLimit0Intr, Cy_HPPASS_SAR_Limit0_Isr);
Cy_SysInt_Init(&sarLimitsIntr, Cy_HPPASS_SAR_Limits_Isr);
Cy_SysInt_Init(&hppassMMIOIntr, Cy_HPPASS_MMIO_Combined_Isr);
/* Set interrupt mask */
}

Also, initialize the NVIC through a separate function as well.

/* Clear pending AC and SAR interrupts in NVIC and Enable that interrupts */
static void My_NVIC_Interrupt_Enable()
{
NVIC_ClearPendingIRQ(sarGroup0Intr.intrSrc);
NVIC_EnableIRQ(sarGroup0Intr.intrSrc);
NVIC_ClearPendingIRQ(sarResultsIntr.intrSrc);
NVIC_EnableIRQ(sarResultsIntr.intrSrc);
NVIC_ClearPendingIRQ(sarLimit0Intr.intrSrc);
NVIC_EnableIRQ(sarLimit0Intr.intrSrc);
NVIC_ClearPendingIRQ(sarLimitsIntr.intrSrc);
NVIC_EnableIRQ(sarLimitsIntr.intrSrc);
NVIC_ClearPendingIRQ(hppassMMIOIntr.intrSrc);
NVIC_EnableIRQ(hppassMMIOIntr.intrSrc);
}

The interrupt service routine for each of the interrupt sources must be implemented in the project. One of those interrupt service routines is shown below:

/* Service Routine for Group0 interrupt of the SAR */
void Cy_HPPASS_SAR_Group0_Isr()
{
/* SAR Group0 Interrupt Clearing */
if (0UL != (CY_HPPASS_INTR_SAR_RESULT_GROUP_0 & intStatus))
{
/* The ADC results can be read here */
}
}

The configuration and initialization sequence for SAR interrupts is shown in the snippet below:

int main(void)
{
/* Set up internal routing, pins, and clock-to-peripheral connections */
init_cycfg_all();
Cy_SCB_UART_Init(UART_HW, &UART_config, &UART_context);
printf("--- HPPASS INTR Test Application ---\r\n");
Cy_GPIO_Write(LED_RED_PORT, LED_RED_PIN, 0);
printf("Test Application Configuring...\r\n");
My_HPPASS_Interrupt_Config();
__disable_irq();
My_NVIC_Interrupt_Enable();
/* Initialize HPPASS */
if (CY_HPPASS_SUCCESS != Cy_HPPASS_Init(&cfg))
{
printf("Cy_HPPASS_Init returns error!!!\r\n");
}
if (CY_HPPASS_SUCCESS != Cy_HPPASS_AC_Start(0U, 0U))
{
printf("Cy_HPPASS_AC_Start returns error!!!\r\n");
}
printf("Infinite loop Started...\r\n");
/* Enable interrupts */
__enable_irq();
for (;;)
{
}
}

To generate SAR Limit or Limits interrupts, configure one or more limits and determine the limit for each SAR channel if needed.

/* The limit crossing detection configuration */
const cy_stc_hppass_sar_limit_t limitCfg0 =
{
.low = 0x03UL,
.high = 0xFFUL
};
/* Channel Configuration */
const cy_stc_hppass_sar_chan_t chanCfg =
{
.diff = false,
.sign = false,
.result = true,
};
const cy_stc_hppass_sar_chan_t chanCfg0 =
{
.diff = false,
.sign = false,
.result = true,
};

That configurations must be also included in the fields of the SAR configuration structure (cy_stc_hppass_sar_t):

.chan = {&chanCfg0, &chanCfg1, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg,
&chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg, &chanCfg},
.grp = {&grpCfg0, &grpCfg1, &grpCfg2, &grpCfg3, &grpCfg4, &grpCfg5, &grpCfg6, &grpCfg7},
.limit = {&limitCfg0, &limitCfg1, NULL, NULL, NULL, NULL, NULL, NULL},

FIFO Interrupts

Using FIFO with MTB Device Configurator, since the FIFO has a single interrupt vector and need to be integrated with different solution personalities (like Motor Control) the Device Configurator itself generates the interrupt handler for entire FIFO with possibility to register individual callback for each FIFO buffer. See the generated source cycfg_peripherals.c for details. The runtime FIFO interrupt control can be done by the Cy_HPPASS_FIFO_SetInterruptMask. The Device Configurator also generates the CYCFG_HPPASS_FIFO_INTR definition - the mask of all the used FIFO interrupt flags, which can be used with Cy_HPPASS_FIFO_SetInterruptMask. When the HPPASS configurator 'start' feature is used - the Cy_HPPASS_FIFO_SetInterruptMask(CYCFG_HPPASS_FIFO_INTR) shall be called automatically during the generated init_cycfg_peripherals(); execution.

hppass_fifo_intr.png

The Device Configurator generated HPPASS FIFO interrupt priority is 0 (because it is intended to drive the solution fast control loop), however it could be changed manually in the generated cycfg_HPPASS_FIFO_interrupt structure before the generated cycfg_HPPASS_FIFO_ISR_Init() execution (when the HPPASS Startup Initialize feature is disabled).

FIR Filter Design

The finite impulse response (FIR) is a generalized filter structure that allows getting all of the basic response types through varying its coefficients. Although the FIR structure allows implementing Low-pass filter (LPF), High-pass filter (HPF), Band-pass filter (BPF), and Band-stop filter (BSF), the recommended filter implementation in HPPASS CSG module is the LPF. Such a recommendation is based on a hardware HPPASS SAR FIR limitation, which is a maximum number of tap count equal to 16 taps. You can use any available FIR Calculator or FIR Design Tool for coefficient determination.
However, the chosen tool must allow you to:

Note
The term Tap Quantity is similar to the Filter Length and is equal to the number of multipliers or coefficients in its structure.
The term Filter Order determines the number of states or input signal delays in the filter structure and is equal to the adders quantity.
The Filter Order can be calculated as follows:
FilterOrder = TapsQuantity - 1

There are various methods for FIR filter design to calculate FIR coefficients. Some tools allow you to choose the design method, but regardless of the exact chosen method, most FIR design tools require determining the desired frequency response parameters.
Generally, in case of the LPF FIR design that will be:

hppass_fir_frequency_response.png

The design method and parameters chosen ultimately determine the values of the filter coefficients.
After configuring the FIR filter and calculating the coefficients, you must check the obtained coefficient values. Due to the hardware HPPASS SAR FIR limitation, all filter coefficients must satisfy the conditions:

(abs(Coef[0..15]) < 1) && (sum(abs(Coef[0..15])) < 8)

If the obtained coefficients didn't comply with these conditions, you must change the FIR filter configurations. The most impact parameters to change the coefficients' values are the Sample Frequency and Transition Band width.
After calculating the coefficients and verifying the conditions, you must convert the floating-point coefficients to a fixed-point representation supported by the hardware.
The HPPASS SAR FIR stores its coefficients in the less significant 16 bits of the 32-bit registers in Q15 fixed-point format.

Note
The Q15 fixed-point format implies that the 15 less significant bits of the number represent its fractional part. Because the whole coefficient is a 16-bit value,
and 15 bits are reserved for the fractional part, the most significant bit is used as a sign extension. That is why the coefficients of the HPPASS SAR FIR cannot have an
integer part and their absolute value must be less than one, and the accurate coefficient values range is from -1 to 1-1/2^15.

To convert the floating-point coefficients to a Q15 fixed-point representation, use the equation below:

Q15coef = round(DECcoef * 2^15)

API Reference

 Macros
 
 Functions
 
 Data Structures
 
 Enumerated Types