Skip to content

File ns_tempco.c

File List > apollo4 > ns_tempco.c

Go to the documentation of this file

#if defined(NS_AMBIQSUITE_VERSION_R4_1_0) || defined(AM_PART_APOLLO4L)
// TEMPCO not supported in this version
#else

    #include "ns_tempco.h"
    #include "am_bsp.h"
    #include "am_mcu_apollo.h"
    #include "am_util.h"
    #include "ns_ambiqsuite_harness.h"
    #include "ns_core.h"
    #include "ns_timer.h"

uint32_t g_ns_tempco_ui32TempcoIsrRet;
uint32_t g_ns_tempco_ui32TempcoADCslot;
am_hal_adc_sample_t g_ns_tempco_sSamples[AM_HAL_TEMPCO_NUMSAMPLES];
void *g_ns_tempco_ADCHandle;

static uint32_t
adc_temperature_samples_get(uint32_t ui32NumSamples, am_hal_adc_sample_t sSamples[]);
static void adc_trigger_wait(void);
static void ns_tempco_callback(ns_timer_config_t *c);

ns_timer_config_t g_ns_tempcoTimer = {
    .api = &ns_timer_V1_0_0,
    .timer = NS_TIMER_TEMPCO,
    .enableInterrupt = true,
    .periodInMicroseconds = 10 * 1024, // 10 seconds
    .callback = ns_tempco_callback};

//*****************************************************************************
//
// ADC and TempCo initialization
//
// For use in TempCo, the ADC must be initialized, powered, configured.
// Following the call to am_hal_pwrctrl_tempco_init(), then it must be
// enabled via a call to am_hal_adc_enable().
//
//*****************************************************************************
uint32_t ns_tempco_init(void) {
    uint32_t ui32Retval;
    am_hal_adc_config_t sADC_Cfg = {
        .eClock = AM_HAL_ADC_CLKSEL_HFRC_24MHZ,     // Select the ADC Clock source
        .ePolarity = AM_HAL_ADC_TRIGPOL_RISING,     // Polarity
        .eTrigger = AM_HAL_ADC_TRIGSEL_SOFTWARE,    // ADC trigger source
        .eClockMode = AM_HAL_ADC_CLKMODE_LOW_POWER, // Clock mode
        .ePowerMode = AM_HAL_ADC_LPMODE1,           // Power mode for idle state
        .eRepeat = AM_HAL_ADC_SINGLE_SCAN,
        .eRepeatTrigger = AM_HAL_ADC_RPTTRIGSEL_TMR};

    // Set the slot to use for temperature
    g_ns_tempco_ui32TempcoADCslot = TEMPCO_ADC_TEMPERATURE_SLOT;

    // Initialize the ADC and get the handle.
    if (am_hal_adc_initialize(0, &g_ns_tempco_ADCHandle) != AM_HAL_STATUS_SUCCESS) {
        ns_printf("tempco_init() Error - reservation of the ADC instance failed.\n");
        return 1;
    }

    // Power on the ADC.
    if (am_hal_adc_power_control(g_ns_tempco_ADCHandle, AM_HAL_SYSCTRL_WAKE, false) !=
        AM_HAL_STATUS_SUCCESS) {
        ns_printf("tempco_init() Error - ADC power on failed.\n");
        return 2;
    }

    // Configure the ADC.
    if (am_hal_adc_configure(g_ns_tempco_ADCHandle, (am_hal_adc_config_t *)&sADC_Cfg) !=
        AM_HAL_STATUS_SUCCESS) {
        ns_printf("tempco_init() Error - configuring ADC failed.\n");
        return 3;
    }

    // Configure and init the timer
    ns_timer_init(&g_ns_tempcoTimer);

    // Initialize the TempCo low power
    ui32Retval = am_hal_pwrctrl_tempco_init(g_ns_tempco_ADCHandle, g_ns_tempco_ui32TempcoADCslot);
    if (ui32Retval != AM_HAL_STATUS_SUCCESS) {
        ns_printf("ERROR am_hal_pwrctrl_tempco_init() returned %d.\n", ui32Retval);
        return 4;
    }

    // Enable the ADC.
    am_hal_adc_enable(g_ns_tempco_ADCHandle);

    g_ns_state.tempcoCurrentlyEnabled = true;
    g_ns_state.tempcoWantsToBeEnabled = true;

    return 0;
}

// timer ISR callback
static void ns_tempco_callback(ns_timer_config_t *c) {
    // Power up, configure, and enable the ADC.
    am_hal_adc_power_control(g_ns_tempco_ADCHandle, AM_HAL_SYSCTRL_WAKE, true);

    // Enable the ADC.
    am_hal_adc_enable(g_ns_tempco_ADCHandle);

    // Call the TempCo ISR
    // Get temperature samples to send to the ISR
    adc_temperature_samples_get(AM_HAL_TEMPCO_NUMSAMPLES, g_ns_tempco_sSamples);

    g_ns_tempco_ui32TempcoIsrRet =
        am_hal_pwrctrl_tempco_sample_handler(AM_HAL_TEMPCO_NUMSAMPLES, g_ns_tempco_sSamples);
    if (g_ns_tempco_ui32TempcoIsrRet != AM_HAL_STATUS_SUCCESS) {
        //
        // One of the primary reasons the handler might return non-success would
        // be if the device is not enabled for TempCo. A fail condition should be
        // handled appropriately here.
        //
    }

    // Disable and power down the ADC.
    am_hal_adc_power_control(g_ns_tempco_ADCHandle, AM_HAL_SYSCTRL_DEEPSLEEP, true);
}

// ****************************************************************************
// Function to trigger the ADC and wait for a value in the FIFO.
// ****************************************************************************
static void adc_trigger_wait(void) {
    // Trigger and wait for something to show up in the FIFO.
    uint32_t ui32Cnt0;

    ui32Cnt0 = _FLD2VAL(ADC_FIFO_COUNT, ADC->FIFO);
    while (_FLD2VAL(ADC_FIFO_COUNT, ADC->FIFO) == ui32Cnt0) {
        am_hal_adc_sw_trigger(g_ns_tempco_ADCHandle);
        am_hal_delay_us(1);
    }
} // adc_trigger_wait()

// ****************************************************************************
// Get samples from temperature sensor.
// ****************************************************************************
static uint32_t
adc_temperature_samples_get(uint32_t ui32NumSamples, am_hal_adc_sample_t sSamples[]) {
    uint32_t ux, ui32OneSample;

    ui32OneSample = 1;

    sSamples[0].ui32Sample = sSamples[1].ui32Sample = sSamples[2].ui32Sample =
        sSamples[3].ui32Sample = sSamples[4].ui32Sample = 0;
    ux = 0;
    while (ux < ui32NumSamples) {
        adc_trigger_wait();

        // Invalidate DAXI to make sure CPU sees the new data when loaded.
        am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, NULL);
        am_hal_adc_samples_read(g_ns_tempco_ADCHandle, true, NULL, &ui32OneSample, &sSamples[ux]);

        if (sSamples[ux].ui32Slot == g_ns_tempco_ui32TempcoADCslot) {
            // This is a temperature sample. Get the next sample.
            ux++;
        } else {
            // This sample is something other than a temperature sample.
            // It should be handled appropriately.
        }
    }

    return AM_HAL_STATUS_SUCCESS;

} // adc_temperature_samples_get()

#endif