Electronic – What are ADC channel “map,” “max,” and “amount” used for on a Microchip ATSAML21 ARM MCU

adcarmmicrochipmicrocontroller

I'm working with a Microchip ATSAML21J18B ARM microcontroller and learning how to set up an ADC input. Coming from the AVR world, things are rather more complicated.

The ADC features (datasheet pg 1030, §42.4) indicate that there are up to 20 analog inputs. Examining the I/O multiplexing section (pg 29-30, §7.1), I can see that there are 20 AIN[xx] designations in the ADC column of the pin function table. I believe I correctly understand that some of these pins reference VDDANA, VDDIO, or VSWOUT based on the values in the Supply column.

I understand that you can also combine channels for various reasons that I'm not familiar with.

Using Atmel "Start", it has generated the following ADC init method:

int32_t adc_async_init(struct adc_async_descriptor *const descr,
    void *const hw,
    uint8_t *channel_map,
    uint8_t channel_max,
    uint8_t channel_amount,
    struct adc_async_channel_descriptor *const descr_ch,
    void *const func)
{
    int32_t init_status;
    struct _adc_async_device *device;
    ASSERT(descr && hw && channel_map && channel_amount && descr_ch);
    ASSERT(channel_amount <= (channel_max + 1));

    device = &descr->device;

    for (uint8_t i = 0; i <= channel_max; i++)
        channel_map[i] = 0xFF;

    descr->channel_map    = channel_map;
    descr->channel_max    = channel_max;
    descr->channel_amount = channel_amount;
    descr->descr_ch       = descr_ch;
    init_status           = _adc_async_init(device, hw);

    if (init_status)
        return init_status;

    device->adc_async_ch_cb.convert_done = adc_async_channel_conversion_done;
    device->adc_async_cb.window_cb       = adc_async_window_threshold_reached;
    device->adc_async_cb.error_cb        = adc_async_error_occured;

    return ERR_NONE;
}

My question is, what are the arguments map, max, and amount for?

The generated example shows the call to this method as so:

// Definitions preceding main()
#define ADC_0_CH_AMOUNT 1
#define ADC_0_CH_MAX 0
struct adc_async_descriptor         ADC_0;
struct adc_async_channel_descriptor ADC_0_ch[ADC_0_CH_AMOUNT];
static uint8_t                      ADC_0_map[ADC_0_CH_MAX + 1];

// ADC init
adc_async_init(&ADC_0,
    ADC,
    ADC_0_map,
    ADC_0_CH_MAX,
    ADC_0_CH_AMOUNT,
    &ADC_0_ch[0],
    (void *)NULL);

I assume these have something to do with combining channels, but I admit I'm very confused about how to set up a single channel just to do a basic 8-bit conversion.

Perhaps a better question title would be, "Explain Microchip/Atmel's ADC implementation on ATSAML21 like I'm 5!" There are so many extra features and options that I'm completely lost.

Best Answer

I am not familiar with this tool, but it seems that the definition of struct adc_async_descriptor is in hal_adc_async.h file:

/**
 * \brief ADC descriptor
 */
struct adc_async_descriptor {
    /** ADC device */
    struct _adc_async_device device;
    /** ADC callbacks type */
    struct adc_async_callbacks adc_async_cb;
    /** Enabled channel map */
    uint8_t *channel_map;
    /** Enabled maximum channel number */
    uint8_t channel_max;
    /** Enabled channel amount */
    uint8_t channel_amount;
    /** ADC channel descriptor */
    struct adc_async_channel_descriptor *descr_ch;
};

Also adc_async_init function and struct adc_async_channel_descriptor are documented in the same file.

Based on the code in hal_adc_async.c, I guess channel_map contains ADC channel indexes used in your application. I am not really sure what's the difference between channel_max and channel_amount.

Ultimately the best way to understand any hardware abstraction code is to see what registers it is accessing. It might be easier though to simply study peripheral description and write the code directly accessing its registers.