📄 lh79524_adc_driver.c
字号:
adc_ch_cfgptr->bias);
/* Write registers */
adccfgptr->regptr->adchicl[adccfgptr->conv_count] = tmphi;
adccfgptr->regptr->adclocl[adccfgptr->conv_count] = tmplo;
/* Update the number of conversions in the sequence */
tmphi = adccfgptr->regptr->adcpcr & ~ADC_NOC_MASK;
adccfgptr->regptr->adcpcr = (tmphi | adccfgptr->conv_count);
/* Save key return value */
status = (STATUS) adccfgptr->conv_count;
/* Increment conversion count value */
adccfgptr->conv_count++;
}
return status;
}
/***********************************************************************
*
* Function: adc_chg_sequence_entry
*
* Purpose: Change an existing sequence entry
*
* Processing:
* If the sequence key (in the ADC_CH_CONV_T structure) is not
* within the limits of the converion list, return _ERROR to the
* caller. Otherwise, generate the new high and low configuration
* words for the channel indicated by the sequence key and update
* the registers in the ADC for that channel. Return _NO_ERROR to
* the caller.
*
* Parameters:
* adc_ch_cfgptr: Pointer to a channel configuration structure
* adccfgptr: Pointer to ADC config structure
*
* Outputs: None
*
* Returns: _ERROR is the sequence key is invalid, otherwise _NO_ERROR.
*
* Notes: None
*
**********************************************************************/
static STATUS adc_chg_sequence_entry(ADC_CH_CONV_T *adc_ch_cfgptr,
ADC_CFG_T *adccfgptr)
{
UNS_32 tmphi, tmplo;
STATUS status = _ERROR;
/* Make sure the passed sequence entry is valid */
if (adc_ch_cfgptr->chkey <= adccfgptr->conv_count)
{
/* Key is valid */
/* Build the high and low control words based on the passed
channel configuration values */
tmphi = (ADC_SETTIME(adc_time_2_clock(adccfgptr, adc_ch_cfgptr->settle_time))
| ADC_INPSEL(adc_ch_cfgptr->inpc)
| ADC_INNSEL(adc_ch_cfgptr->innc)
| ADC_REFP_SEL(adc_ch_cfgptr->vrefp));
/* Build and save the control bank low word register */
tmplo = (ADC_REFN_SEL(adc_ch_cfgptr->vrefn) |
adc_ch_cfgptr->bias);
/* Write registers */
adccfgptr->regptr->adchicl[adc_ch_cfgptr->chkey] = tmphi;
adccfgptr->regptr->adclocl[adc_ch_cfgptr->chkey] = tmplo;
status = _NO_ERROR;
}
return status;
}
/***********************************************************************
*
* Function: adc_ring_fill
*
* Purpose: Move data from the ADC FIFO to the driver ring buffer
*
* Processing:
* While the ADC FIFO is not empty, copy an entry from the ADC
* FIFO into the ADC driver ring buffer. Increment the ring buffer
* head pointer. If it exceeds the ring buffer size, reset the
* head pointer to 0.
*
* Parameters:
* adccfgptr: Pointer to ADC config structure
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
static void adc_ring_fill(ADC_CFG_T *adccfgptr)
{
ADC_REGS_T *adcregsptr = (ADC_REGS_T *) adccfgptr->regptr;
/* Continue stuffing the receive ring FIFO until the receive
FIFO is empty */
while ((adcregsptr->adcfifosts & ADC_FIFO_EMPTY) == 0)
{
adccfgptr->rx[adccfgptr->rx_head] =
(UNS_16) adcregsptr->adcresults;
/* Increment receive ring buffer head pointer */
adccfgptr->rx_head++;
if (adccfgptr->rx_head >= ADC_RING_BUFSIZE)
{
adccfgptr->rx_head = 0;
}
}
}
/***********************************************************************
*
* Function: adc_setup_4wire_touchscreen
*
* Purpose:
* Set up the sequencer for a 4-wire touch screen measurement.
*
* Processing:
* Initialize the adc to its default state.
* Map all touchscreen pins to ADC input
* Set up the idle step to prevent false pen auto-triggering.
* Flush the result FIFO.
* Clear the pen and end of sequence interrupts.
* Set up the sequence as follows:
* 0. Strong pullup on X+ pin, other pins float.
* Measure on pin x+. This measurement will be discarded.
* This step de-glitches any partial triggers.
* 1. Weak pullup on X+ pin, X- floats, Y- to Ground and neg
* ref, Y+ floats (ratiometric).
* Measure on X+ pin. This measurement is used to verify
* the pen was down at the beginning of the coordinate
* measurement.
* 2. X+ and X- float, Y- to Ground and neg
* ref, Y+ to VDDA_ADC and positive reference (ratiometric).
* Measure on pin x+. This is the X measurement.
* 3. Repeat the X measurement 3 more times (we will average
* 4 measurements to improve signal-to-noise.
* 4. Y+ and Y- float, X- to Ground and neg
* ref, X+ to VDDA_ADC and positive reference (ratiometric).
* Measure on pin Y+. This is the Y measurement.
* 5. Repeat the Y measurement 3 more times (we will average
* 4 measurements to improve signal-to-noise.
* 6. Strong pullup on X+ pin, other pins float.
* Measure on pin x+. This measurement will be discarded.
* This step de-glitches any partial triggers.
* 7. Weak pullup on X+ pin, X- floats, Y- to Ground and neg
* ref, Y+ floats (ratiometric).
* Measure on X+ pin. This measurement is used to verify
* the pen was down at the end of the coordinate
* measurement.
*
* Parameters:
* tsc_cfg: Pointer to touch screen config structure
* adccfgptr: Pointer to ADC config structure
*
* Outputs: None.
*
* Returns: Nothing
*
* Notes:
* This ADC configuration is intended to be used in conjunction
* with an end of sequence interrupt handler that follows the following
* algorithm
* 1. Read and discard the first measurement in the result FIFO
* 2. Read the 2nd result. If the measured voltage is below a
* threashhold, then the pen is down, otherwise it is up. If
* the pen is up, read and discard the remaining measurements;
* then return from interrupt.
* 3. Pen is down. Read and average the next 4 results as the X
* coordinate.
* 4. Read and average the next 4 results as the Y coordinate
* measurement.
* 5 Read and discard the next result.
* 6. Read the last FIFO result. If the measured voltage is
* below a threashhold, then the pen is still down, otherwise
* it is up. If the pen is up, return from interrupt. If the
* pen is still down, report the new X and Y measurements.
*
* There are sevreal ways to trigger measurements.
* The recomended way that is more power efficient is to set up a a pen
* interrupt handler that switches the ADC module for pen-triggered
* to soft_triggered measurements. Initially, the ADC is set up
* for pen-triggered measurements. On pen down, the pen interrupt
* handler switches the ADC to software-triggered measurements.
* The system polls the touch screen periodically
* until the end of sequence interrupt handler detects pen up.
* The handler then switches the ADC back to pen-triggered measurements.
*
**********************************************************************/
static STATUS adc_setup_4wire_touchscreen(ADC_TSC_CONV_T* tsc_cfg,
ADC_CFG_T *adccfgptr)
{
ADC_CH_CONV_T step; /* a step in the sequence*/
ADC_REGS_T *adcregsptr = adccfgptr->regptr;
UNS_32 tmp;
ADC_VREFP_T pen_detect_p = ADC_REFP_VREF;
ADC_VREFN_T pen_detect_n = ADC_REFN_VREF;
while ((adcregsptr->adcfifosts & ADC_FIFO_EMPTY) == 0)
{
tmp = adcregsptr->adcresults;
}
adcregsptr->adcic = (ADC_EOS_CLR | ADC_PEN_CLR);
/* Empty ring buffer and set conversion counter
to 0 */
adccfgptr->rx_head = adccfgptr->rx_tail = 0;
adccfgptr->conv_count = 0;
/* It is only necessary to turn on the reference buffer if the on-chip
reference is used as the positive reference for a measurement. If
an external reference is used (e.g. for ratiometric measurements),
then the reference buffer can be off (saves power) */
if(tsc_cfg->vrefp_x != ADC_REFP_VN8)
{
adcregsptr->adcpcr |= ADC_REF_ENABLE;
}
else
{
pen_detect_p = tsc_cfg->vrefp_x;
pen_detect_n = tsc_cfg->vrefn_x;
}
/* Build and save the idle channel step */
tmp = (ADC_SETTIME(adc_time_2_clock(adccfgptr, tsc_cfg->settle_time)) |
ADC_INPSEL(ADC_ANALOG_1) |
ADC_INNSEL(ADC_REFN_VREFN) |
ADC_REFP_SEL(pen_detect_p));
adcregsptr->adcidlehi = tmp;
tmp = (ADC_REFN_SEL(pen_detect_n) |
(ADC_FET_AN0_VDDA1K | ADC_FET_AN3_GND));
adcregsptr->adcidlelo = tmp;
/* for rest of the steps keep settling time same */
step.settle_time = tsc_cfg->settle_time;
/* Build step 0 - prior to 1st pen-down check*/
step.inpc = ADC_ANALOG_0;
step.innc = ADC_REFN_VREFN;
step.vrefp = pen_detect_p;
step.vrefn = pen_detect_n;
step.bias = ADC_FET_AN0_VDDA;
adc_add_sequence_entry(&step, adccfgptr);
/* Build step 1 - check pen down state prior to coords*/
step.inpc = ADC_ANALOG_0;
step.innc = ADC_REFN_VREFN;
step.vrefp = pen_detect_p;
step.vrefn = pen_detect_n;
step.bias = (ADC_FET_AN0_VDDA1K | ADC_FET_AN3_GND);
adc_add_sequence_entry(&step, adccfgptr);
/* Build step 2,3,4 & 5 - measure x coords*/
for(tmp = 0; tmp < 4; tmp++)
{
step.inpc = ADC_ANALOG_2;
step.innc = ADC_REFN_VREFN;
step.vrefp = tsc_cfg->vrefp_x;
step.vrefn = tsc_cfg->vrefn_x;
step.bias = (ADC_FET_AN1_GND | ADC_FET_AN0_VDDA);
adc_add_sequence_entry(&step, adccfgptr);
}
/* Build step 6,7,8 & 9 - measure y coords*/
for(tmp = 0; tmp < 4; tmp++)
{
step.inpc = ADC_ANALOG_0;
step.innc = ADC_REFN_VREFN;
step.vrefp = tsc_cfg->vrefp_y;
step.vrefn = tsc_cfg->vrefn_y;
step.bias = (ADC_FET_AN3_GND | ADC_FET_AN2_VDDA);
adc_add_sequence_entry(&step, adccfgptr);
}
/* Build step 10 - prior to last pen-down check*/
step.inpc = ADC_ANALOG_0;
step.innc = ADC_REFN_VREFN;
step.vrefp = pen_detect_p;
step.vrefn = pen_detect_n;
step.bias = ADC_FET_AN0_VDDA;
adc_add_sequence_entry(&step, adccfgptr);
/* Build step 11 - prior to last pen-down check*/
step.inpc = ADC_ANALOG_0;
step.innc = ADC_REFN_VREFN;
step.vrefp = pen_detect_p;
step.vrefn = pen_detect_n;
step.bias = (ADC_FET_AN0_VDDA1K | ADC_FET_AN3_GND);
adc_add_sequence_entry(&step, adccfgptr);
return _NO_ERROR;
}
/***********************************************************************
*
* Function: adc_setup_5wire_touchscreen
*
* Purpose:
* Set up the sequencer for a 5-wire touch screen measurement.
*
* Processing:
* Initialize the adc to its default state.
* Map all touchscreen pins to ADC input
* Set up the idle step to prevent false pen auto-triggering.
* Flush the result FIFO.
* Clear the pen and end of sequence interrupts.
* Set up the sequence as follows:
* 0. Strong pullup on UL pin, other pins float.
* Measure on pin x+. This measurement will be discarded.
* This step de-glitches any partial triggers.
* 1. Weak pullup on UL pin, wiper to VSSA_ADC, other pins float.
* Measure on UL pin. This measurement is used to verify
* the pen was down at the beginning of the coordinate
* measurement.
* 2. UL and LL to VDDA_ADC. UR and LR to VSSA_ADC.
* UL to positive reference and LR to negative reference
* (ratiometric). Wiper floats.
* Measure on pin Wiper. This is the X measurement.
* 3. Repeat the X measurement 3 more times (we will average
* 4 measurements to improve signal-to-noise.
* 4. UL and UR to VDDA_ADC. LL and LR to VSSA_ADC.
* UL to positive reference and LR to negative reference
* (ratiometric). Wiper floats.
* Measure on pin Wiper. This is the Y measurement.
* 5. Repeat the Y measurement 3 more times (we will average
* 4 measurements to improve signal-to-noise.
* 6. Strong pullup on UL pin, other pins float.
* Measure on pin UL. This measurement will be discarded.
* This step de-glitches any partial triggers.
* 7. Weak pullup on UL pin, wiper to ground.
* Measure on X+ pin. This measurement is used to verify
* the pen was down at the end of the coordinate
* measurement.
*
* Parameters:
* tsc_cfg: Pointer to touch screen config structure
* adccfgptr: Pointer to ADC config structure
*
* Outputs: None.
*
* Returns: Nothing
*
* Notes:
* This ADC configuration is intended to be used in conjunction
* with an end of sequence interrupt handler that follows the following
* algorithm
* 1. Read and discard the first measurement in the result FIFO
* 2. Read the 2nd result. If the measured voltage is below a
* threashhold, then the pen is down, otherwise it is up. If
* the pen is up, read and discard the remaining measurements;
* then return from interrupt.
* 3. Pen is down. Read and average the next 4 results as the X
* coordinate.
* 4. Read and average the next 4 results as the Y coordinate
* measurement.
* 5 Read and discard the next result.
* 6. Read the last FIFO result. If the measured voltage is
* below a threashhold, then the pen is still down, otherwise
* it is up. If the pen is up, return from interrupt. If the
* pen is still down, report the new X and Y measurements.
*
* There are sevreal ways to trigger measurements.
* The recomended way that is more power efficient is to set up a a pen
* interrupt handler that switches the ADC module for pen-triggered
* to soft_triggered measurements. Initially, the ADC is set up
* for pen-triggered measurements. On pen down, the pen interrupt
* handler switches the ADC to software-triggered measurements.
* The system polls the touch screen periodically
* until the end of sequence interrupt handler detects pen up.
* The handler then switches the ADC back to pen-triggered measurements.
*
**********************************************************************/
static STATUS adc_setup_5wire_touchscreen(ADC_TSC_CONV_T* tsc_cfg,
ADC_CFG_T *adccfgptr)
{
ADC_CH_CONV_T step; /* a step in the sequence*/
ADC_REGS_T *adcregsptr = adccfgptr->regptr;
UNS_32 tmp;
ADC_VREFP_T pen_detect_p = ADC_REFP_VREF;
ADC_VREFN_T pen_detect_n = ADC_REFN_VREF;
while ((adcregsptr->adcfifosts & ADC_FIFO_EMPTY) == 0)
{
tmp = adcregsptr->adcresults;
}
adcregsptr->adcic = (ADC_EOS_CLR | ADC_PEN_CLR);
/* Empty ring buffer and set conversion counter
to 0 */
adccfgptr->rx_head = adccfgptr->rx_tail = 0;
adccfgptr->conv_count = 0;
/* It is only necessary to turn on the reference buffer if the on-chip
reference is used as the positive reference for a measurement. If
an external reference is used (e.g. for ratiometric measurements),
then the reference buffer can be off (saves power) */
if(tsc_cfg->vrefp_x != ADC_REFP_VN8)
{
adcregsptr->adcpcr |= ADC_REF_ENABLE;
}
else
{
pen_detect_p = tsc_cfg->vrefp_x;
pen_detect_n = tsc_cfg->vrefn_x;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -