Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nuvoton M487 ADC Accuracy using AnalogIn() #15419

Closed
timothyjager opened this issue May 8, 2023 · 4 comments
Closed

Nuvoton M487 ADC Accuracy using AnalogIn() #15419

timothyjager opened this issue May 8, 2023 · 4 comments

Comments

@timothyjager
Copy link

Description of defect

Nuvoton M480 ADC accuracy is not good when using the mbed AnalogIn() object. This is especially true if there is any inline resistance (high impedance voltage source).

All of the Nuvoton SampleCode projects for the EADC have a line of code that calls the function EADC_SetExtendSampleTime(). For example, if you look at line 79 in EADC_TempSensor/main.c it looks like this

  /* Set sample module 17 external sampling time to 0x3F */
    EADC_SetExtendSampleTime(EADC, 17, 0x3F);

Target(s) affected by this defect ?

This has been observed on the Nuvoton M487

Toolchain(s) (name and version) displaying this defect ?

ARM_GCC 10.3.1

What version of Mbed-os are you using (tag or sha) ?

6.17.0

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

mbed cli 1.10.5

How is this defect reproduced ?

  1. Configure a pin as AnalogIn() and read the value of a known input voltage. Note the accuracy. The accuracy will be much worse if there is any series resistance (e.g. a high impedance voltage source)

  2. Modify mbed function called analogin_init() in analogin_api.c

void analogin_init(analogin_t *obj, PinName pin)
{
    obj->adc = (ADCName) pinmap_peripheral(pin, PinMap_ADC);
    MBED_ASSERT(obj->adc != (ADCName) NC);

    const struct nu_modinit_s *modinit = get_modinit(obj->adc, adc_modinit_tab);
    MBED_ASSERT(modinit != NULL);
    MBED_ASSERT(modinit->modname == (int) obj->adc);

    obj->pin = pin;

    // Wire pinout
    pinmap_pinout(pin, PinMap_ADC);

    EADC_T *eadc_base = (EADC_T *) NU_MODBASE(obj->adc);

    // NOTE: All channels (identified by ADCName) share a ADC module. This reset will also affect other channels of the same ADC module.
    if (! eadc_modinit_mask) {
        // Select clock source of paired channels
        CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv);

        // Enable clock of paired channels
        CLK_EnableModuleClock(modinit->clkidx);

        // Reset this module if no channel enabled
        SYS_ResetModule(modinit->rsetidx);

        // Set the ADC internal sampling time, input mode as single-end and enable the A/D converter
        EADC_Open(eadc_base, EADC_CTL_DIFFEN_SINGLE_END);
    }

uint32_t chn =  NU_MODSUBINDEX(obj->adc);

//--------------ADD THIS LINE OF CODE TO IMPROVE ACCURACY---------------------   
EADC_SetExtendSampleTime(eadc_base, chn, 0xF);  //ADC produces much more accurate readings when this line is added. at least 0xF of extended sample time is needed. more is better.
//----------------------------------------------------------------

    // Configure the sample module Nmod for analog input channel Nch and software trigger source
    EADC_ConfigSampleModule(eadc_base, chn, EADC_SOFTWARE_TRIGGER, chn);

    eadc_modinit_mask |= 1 << chn;
}
  1. Recompile and run the code again and note the accuracy of the ADC reading. It will be improved.

The code above uses a hard-coded value of 0xF. Ideally this would be somehow configurable on a per-channel basis. Is this possible?

@0xc0170
Copy link
Contributor

0xc0170 commented May 16, 2023

#15422 fixes it

@ccli8
Copy link
Contributor

ccli8 commented May 17, 2023

To extend M487 EADC sampling time like below,

//--------------ADD THIS LINE OF CODE TO IMPROVE ACCURACY---------------------   
EADC_SetExtendSampleTime(eadc_base, chn, 0xF);  //ADC produces much more accurate readings when this line is added. at least 0xF of extended sample time is needed. more is better.
//----------------------------------------------------------------

This can be done through M487 target configuration:

mbed-os/targets/targets.json

Lines 7761 to 7763 in 8779918

"eadc-extsmpt-list": {
"help": "For EADC, comma separated {pin, value} list to extend sampling time in EADC clocks on per-pin basis. Value must be in the range [0, 255]."
},

For example, in mbed_app.json, add below to extend EADC sampling time for AudioIn A0/A1 pins.

{
    "target_overrides": {
        "NUMAKER_IOT_M487": {
            "target.eadc-extsmpt-list": "{A0, 20}, {A1, 21}"
        }
}

@0xc0170
Copy link
Contributor

0xc0170 commented May 25, 2023

#15422 was merged, shall this be closed?

@ccli8
Copy link
Contributor

ccli8 commented May 26, 2023

#15422 was merged, shall this be closed?

Yes, this can be closed.

@0xc0170 0xc0170 closed this as completed May 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants