/**
 * @brief Select the analog reference mode and range. Local replacement for ADC_setVREF().
 *
 * Driverlib's ADC_setVREF() gets the external-mode range backwards. The two range
 * enumerators alias -- ADC_REFERENCE_3_3V and ADC_REFERENCE_VREFHI are both 0,
 * ADC_REFERENCE_2_5V and ADC_REFERENCE_2xVREFHI are both 1 -- and it writes the range bits
 * from that value alone, without looking at the mode. The bit means opposite things in the
 * two modes, so asking for ADC_REFERENCE_VREFHI in external mode sets the bits and selects
 * 2x VREFHI: a 6.0 V full scale where 3.0 V was asked for. This version branches on the
 * mode first, then writes the bits to match.
 *
 * It also fixes a second slip: driverlib's VDDA branch writes ANAREFPCTL twice and never
 * touches ANAREFNCTL.
 *
 * TODO: delete this and go back to ADC_setVREF() once TI corrects the driverlib. The
 * driverlib parameter names and structure are kept deliberately, so the two stay easy to
 * diff against each other.
 *
 * @param base       ADC module base address. Only checked, never used: the registers below
 *                   are device-wide, covering ADCA..ADCE together.
 * @param refMode    ADC_REFERENCE_INTERNAL, ADC_REFERENCE_EXTERNAL or ADC_REFERENCE_VDDA
 * @param refVoltage internal: ADC_REFERENCE_3_3V or ADC_REFERENCE_2_5V.
 *                   external: ADC_REFERENCE_VREFHI (full scale = VREFHI) or
 *                   ADC_REFERENCE_2xVREFHI (full scale = 2 x VREFHI).
 */
static void ADC_setVREF_corrected(uint32_t base, ADC_ReferenceMode refMode, ADC_ReferenceVoltage refVoltage)
{
    PIXII_ASSERT(base != 0UL);

    EALLOW;

    //
    // Reference source. Each branch covers all five ADCs, because these registers do.
    //
    if (refMode == ADC_REFERENCE_INTERNAL)
    {
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) &=
            ~(ASYSCTL_ANAREF_INTREF_ADCA | ASYSCTL_ANAREF_INTREF_ADCB | ASYSCTL_ANAREF_INTREF_ADCC | ASYSCTL_ANAREF_INTREF_ADCD |
              ASYSCTL_ANAREF_INTREF_ADCE);

        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFNCTL) &=
            ~(ASYSCTL_ANAREF_INTREF_ADCA | ASYSCTL_ANAREF_INTREF_ADCB | ASYSCTL_ANAREF_INTREF_ADCC | ASYSCTL_ANAREF_INTREF_ADCD |
              ASYSCTL_ANAREF_INTREF_ADCE);
    }
    else if (refMode == ADC_REFERENCE_EXTERNAL)
    {
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) =
            (HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) & ~0x3FFU) |
            (ASYSCTL_ANAREF_VREFHI_ADCA | ASYSCTL_ANAREF_VREFHI_ADCB | ASYSCTL_ANAREF_VREFHI_ADCC | ASYSCTL_ANAREF_VREFHI_ADCD |
             ASYSCTL_ANAREF_VREFHI_ADCE);

        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFNCTL) =
            (HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFNCTL) & ~0x3FFU) |
            (ASYSCTL_ANAREF_VREFHI_ADCA | ASYSCTL_ANAREF_VREFHI_ADCB | ASYSCTL_ANAREF_VREFHI_ADCC | ASYSCTL_ANAREF_VREFHI_ADCD |
             ASYSCTL_ANAREF_VREFHI_ADCE);
    }
    else
    {
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) |=
            (ASYSCTL_ANAREF_VDDA_ADCA | ASYSCTL_ANAREF_VDDA_ADCB | ASYSCTL_ANAREF_VDDA_ADCC | ASYSCTL_ANAREF_VDDA_ADCD |
             ASYSCTL_ANAREF_VDDA_ADCE);

        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFNCTL) |=
            (ASYSCTL_ANAREF_VDDA_ADCA | ASYSCTL_ANAREF_VDDA_ADCB | ASYSCTL_ANAREF_VDDA_ADCC | ASYSCTL_ANAREF_VDDA_ADCD |
             ASYSCTL_ANAREF_VDDA_ADCE);
    }

    //
    // Reference range, ANAREFPCTL bits 14:10. This is the half driverlib gets wrong: the
    // same bit value means "3.3 V" internally and "2 x VREFHI" externally, so which
    // enumerator sets it depends on the mode.
    //
    const uint16_t range_mask =
        (uint16_t)((ASYSCTL_ANAREF_ADCA | ASYSCTL_ANAREF_ADCB | ASYSCTL_ANAREF_ADCC | ASYSCTL_ANAREF_ADCD | ASYSCTL_ANAREF_ADCE)
                   << 10);
    int set_range_bits;

    if (refMode == ADC_REFERENCE_EXTERNAL)
    {
        // Set doubles the full scale to 2 x VREFHI; clear leaves it at VREFHI.
        set_range_bits = (refVoltage == ADC_REFERENCE_2xVREFHI) ? 1 : 0;
    }
    else
    {
        // Set selects the 3.3 V internal reference; clear selects 2.5 V.
        set_range_bits = (refVoltage == ADC_REFERENCE_3_3V) ? 1 : 0;
    }

    if (set_range_bits != 0)
    {
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) |= range_mask;
    }
    else
    {
        HWREGH(ANALOGSUBSYS_BASE + ASYSCTL_O_ANAREFPCTL) &= (uint16_t)~range_mask;
    }

    EDIS;
}
