From c19fb2ab58d0ea77263a5eafa28fe2cf6ca9dec6 Mon Sep 17 00:00:00 2001 From: lin <429426691@qq.com> Date: Fri, 15 Sep 2017 18:10:51 +0800 Subject: Add bsp apollo2 --- bsp/apollo2/libraries/drivers/hal/am_hal_adc.c | 553 +++ bsp/apollo2/libraries/drivers/hal/am_hal_adc.h | 348 ++ .../libraries/drivers/hal/am_hal_cachectrl.c | 576 +++ .../libraries/drivers/hal/am_hal_cachectrl.h | 211 + bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.c | 491 +++ bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.h | 206 + bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.c | 1687 ++++++++ bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.h | 278 ++ bsp/apollo2/libraries/drivers/hal/am_hal_debug.c | 81 + bsp/apollo2/libraries/drivers/hal/am_hal_debug.h | 89 + bsp/apollo2/libraries/drivers/hal/am_hal_flash.c | 1449 +++++++ bsp/apollo2/libraries/drivers/hal/am_hal_flash.h | 297 ++ bsp/apollo2/libraries/drivers/hal/am_hal_global.c | 59 + bsp/apollo2/libraries/drivers/hal/am_hal_global.h | 114 + bsp/apollo2/libraries/drivers/hal/am_hal_gpio.c | 503 +++ bsp/apollo2/libraries/drivers/hal/am_hal_gpio.h | 684 +++ .../libraries/drivers/hal/am_hal_i2c_bit_bang.c | 757 ++++ .../libraries/drivers/hal/am_hal_i2c_bit_bang.h | 100 + .../libraries/drivers/hal/am_hal_interrupt.c | 407 ++ .../libraries/drivers/hal/am_hal_interrupt.h | 159 + bsp/apollo2/libraries/drivers/hal/am_hal_iom.c | 4426 ++++++++++++++++++++ bsp/apollo2/libraries/drivers/hal/am_hal_iom.h | 559 +++ bsp/apollo2/libraries/drivers/hal/am_hal_ios.c | 1303 ++++++ bsp/apollo2/libraries/drivers/hal/am_hal_ios.h | 362 ++ bsp/apollo2/libraries/drivers/hal/am_hal_itm.c | 453 ++ bsp/apollo2/libraries/drivers/hal/am_hal_itm.h | 107 + bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.c | 292 ++ bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.h | 212 + bsp/apollo2/libraries/drivers/hal/am_hal_otp.c | 173 + bsp/apollo2/libraries/drivers/hal/am_hal_otp.h | 108 + bsp/apollo2/libraries/drivers/hal/am_hal_pdm.c | 158 + bsp/apollo2/libraries/drivers/hal/am_hal_pdm.h | 665 +++ bsp/apollo2/libraries/drivers/hal/am_hal_pin.h | 557 +++ bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.c | 558 +++ bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.h | 342 ++ bsp/apollo2/libraries/drivers/hal/am_hal_queue.c | 286 ++ bsp/apollo2/libraries/drivers/hal/am_hal_queue.h | 123 + bsp/apollo2/libraries/drivers/hal/am_hal_reset.c | 160 + bsp/apollo2/libraries/drivers/hal/am_hal_reset.h | 119 + bsp/apollo2/libraries/drivers/hal/am_hal_rtc.c | 678 +++ bsp/apollo2/libraries/drivers/hal/am_hal_rtc.h | 185 + bsp/apollo2/libraries/drivers/hal/am_hal_stimer.c | 525 +++ bsp/apollo2/libraries/drivers/hal/am_hal_stimer.h | 242 ++ bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c | 851 ++++ bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.h | 119 + bsp/apollo2/libraries/drivers/hal/am_hal_systick.c | 453 ++ bsp/apollo2/libraries/drivers/hal/am_hal_systick.h | 83 + bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.c | 381 ++ bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.h | 193 + bsp/apollo2/libraries/drivers/hal/am_hal_ttp.c | 205 + bsp/apollo2/libraries/drivers/hal/am_hal_ttp.h | 72 + bsp/apollo2/libraries/drivers/hal/am_hal_uart.c | 1160 +++++ bsp/apollo2/libraries/drivers/hal/am_hal_uart.h | 345 ++ bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.c | 287 ++ bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.h | 176 + bsp/apollo2/libraries/drivers/hal/am_hal_wdt.c | 454 ++ bsp/apollo2/libraries/drivers/hal/am_hal_wdt.h | 184 + 57 files changed, 26605 insertions(+) create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_adc.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_adc.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_debug.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_debug.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_flash.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_flash.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_global.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_global.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_gpio.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_gpio.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_iom.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_iom.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ios.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ios.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_itm.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_itm.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_otp.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_otp.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_pdm.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_pdm.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_pin.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_queue.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_queue.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_reset.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_reset.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_rtc.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_rtc.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_stimer.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_stimer.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_systick.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_systick.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ttp.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_ttp.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_uart.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_uart.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.h create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_wdt.c create mode 100644 bsp/apollo2/libraries/drivers/hal/am_hal_wdt.h (limited to 'bsp/apollo2/libraries/drivers/hal') diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_adc.c b/bsp/apollo2/libraries/drivers/hal/am_hal_adc.c new file mode 100644 index 0000000000..957408d0e5 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_adc.c @@ -0,0 +1,553 @@ +//***************************************************************************** +// +// am_hal_adc.c +//! @file +//! +//! @brief Functions for interfacing with the Analog to Digital Converter. +//! +//! @addtogroup adc2 Analog-to-Digital Converter (ADC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Private SRAM view of temperature trims. +//! +//! This static SRAM union is private to the ADC HAL functions. +// +//***************************************************************************** +static union +{ + //! These trim values are loaded as uint32_t values. + struct + { + //! Temperature of the package test head (in degrees Kelvin) + uint32_t ui32CalibrationTemperature; + + //! Voltage corresponding to temperature measured on test head. + uint32_t ui32CalibrationVoltage; + + //! ADC offset voltage measured on the package test head. + uint32_t ui32CalibrationOffset; + + //! Flag if default (guess) or measured. + bool bMeasured; + } ui32; + //! These trim values are accessed as floats when used in temp calculations. + struct + { + //! Temperature of the package test head in degrees Kelvin + float fCalibrationTemperature; + + //! Voltage corresponding to temperature measured on test head. + float fCalibrationVoltage; + + //! ADC offset voltage measured on the package test head. + float fCalibrationOffset; + + //! Flag if default (guess) or measured. + float fMeasuredFlag; + } flt; +} priv_temp_trims; + +//***************************************************************************** +// +//! @brief Configure the ADC. +//! +//! @param psConfig - pointer to the configuration structure for the ADC. +//! +//! This function may be used to perform the initial setup of the ADC based on +//! setting found in a configuration structure. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_config(am_hal_adc_config_t *psConfig) +{ + // + // Set general ADC configuration parameters. + // + AM_REG(ADC, CFG) = (psConfig->ui32Clock | + psConfig->ui32TriggerConfig | + psConfig->ui32Reference | + psConfig->ui32ClockMode | + psConfig->ui32PowerMode | + psConfig->ui32Repeat | + AM_REG_ADC_CFG_ADCEN(1)); + + // + // Grab the temperature trims. + // + priv_temp_trims.ui32.ui32CalibrationTemperature = + am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_TEMP_ADDR); + priv_temp_trims.ui32.ui32CalibrationVoltage = + am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_AMBIENT_ADDR); + priv_temp_trims.ui32.ui32CalibrationOffset = + am_hal_flash_load_ui32(AM_HAL_ADC_CALIB_ADC_OFFSET_ADDR); + + if ( (priv_temp_trims.ui32.ui32CalibrationTemperature == 0xffffffff) || + (priv_temp_trims.ui32.ui32CalibrationVoltage == 0xffffffff) || + (priv_temp_trims.ui32.ui32CalibrationOffset == 0xffffffff) ) + { + // + // Since the device has not been calibrated on the tester, we'll load + // default calibration values. These default values should result + // in worst-case temperature measurements of +-6 degress C. + // + priv_temp_trims.flt.fCalibrationTemperature = AM_HAL_ADC_CALIB_TEMP_DEFAULT; + priv_temp_trims.flt.fCalibrationVoltage = AM_HAL_ADC_CALIB_AMBIENT_DEFAULT; + priv_temp_trims.flt.fCalibrationOffset = AM_HAL_ADC_CALIB_ADC_OFFSET_DEFAULT; + priv_temp_trims.ui32.bMeasured = false; + } + else + { + priv_temp_trims.ui32.bMeasured = true; + } +} + +//***************************************************************************** +// +//! @brief Get the temperature trim parameters after configuring the ADC. +//! +//! @param pfTemp - pointer to a location to store the calibration temperature. +//! @param pfVoltage - pointer to a location to store the calibration voltage. +//! @param pfOffsetV - pointer to a location to store the calibration offset. +//! +//! This function may be used to access the actual temperature sensor trim +//! values from the private structure. +//! +//! WARNING: only call this after the ADC has been configured with +//! am_hal_adc_config. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_temp_trims_get(float * pfTemp, float * pfVoltage, float * pfOffsetV) +{ + // + // Return trim temperature as a float, if you can. + // + if ( pfTemp != NULL ) + { + *pfTemp = priv_temp_trims.flt.fCalibrationTemperature; + } + + // + // Return trim voltage as a float, if you can. + // + if ( pfVoltage != NULL ) + { + *pfVoltage = priv_temp_trims.flt.fCalibrationVoltage; + } + + // + // Return trim ADC offset voltage as a float, if you can. + // + if ( pfOffsetV != NULL ) + { + *pfOffsetV = priv_temp_trims.flt.fCalibrationOffset; + } +} + +//***************************************************************************** +// +//! @brief Set the ADC window parameters. +//! +//! @param ui32Upper - the upper limit for the ADC window. +//! @param ui32Upper - the lower limit for the ADC window. +//! +//! This function may be used to change the ADC window parameters. Please note +//! that the upper and lower limits are only 16-bits wide in the ADC hardware. +//! This function will ignore the upper 16 bits of these arguments. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_window_set(uint32_t ui32Upper, uint32_t ui32Lower) +{ + // + // Set the window limits for the ADC. + // + AM_BFW(ADC, WULIM, ULIM, ui32Upper); + AM_BFW(ADC, WLLIM, LLIM, ui32Lower); +} + +//***************************************************************************** +// +//! @brief Configure a single ADC slot. +//! +//! @param ui32SlotNumber - the number of the ADC slot to be configured. +//! @param ui32SlotConfig - contains slot-specific options. +//! +//! This function may be used to configure the settings for an individual ADC +//! slot. The parameter \b ui32SlotConfig should be the logical 'OR' of a slot +//! average macro, a slot hold-time macro, a slot channel macro, and +//! optionally, the slot window enable macro. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_slot_config(uint32_t ui32SlotNumber, uint32_t ui32SlotConfig) +{ + uint32_t ui32RegOffset; + + // + // Make sure we're accessing a real slot. + // + am_hal_debug_assert_msg((ui32SlotNumber & 0xFFFFFFFF0) == 0, + "Trying to configure an ADC slot that doesn't exist."); + + // + // Locate the correct register for this ADC slot. + // + ui32RegOffset = (AM_REG_ADCn(0) + AM_REG_ADC_SL0CFG_O + (4 * ui32SlotNumber)); + + // + // Write the register with the caller's configuration value. + // + AM_REGVAL(ui32RegOffset) = ui32SlotConfig; +} + +//***************************************************************************** +// +//! @brief Peek at the next fifo entry. +//! +//! This function reads the oldest value in the ADC sample fifo but doesn't +//! actually advance the fifo to the next entry. This function is useful when +//! you need information from the fifo but you don't want to also empty the +//! fifo. This could be helpful if you want to check the FIFO depth without +//! pulling any data out. +//! +//! The value returned by this function is the raw 32-bit value provided by the +//! ADC hardware. In order to interpret this value, you will need to use one of +//! the following macros. +//! +//! @return 32-bit FIFO entry. +//! +// +//***************************************************************************** +uint32_t +am_hal_adc_fifo_peek(void) +{ + uint32_t ui32FIFOValue; + + // + // Grab a value from the ADC FIFO. + // + ui32FIFOValue = AM_REG(ADC, FIFO); + + // + // Return FIFO entry. + // + return ui32FIFOValue; +} + +//***************************************************************************** +// +//! @brief +//! +//! This function reads the oldest value in the ADC fifo and then pops the +//! fifo. Use this function when you actually want to pull data out of the +//! fifo. +//! +//! @return 32-bit FIFO entry. +//! +// +//***************************************************************************** +uint32_t +am_hal_adc_fifo_pop(void) +{ + uint32_t ui32FIFOValue; + + // + // Grab a value from the ADC FIFO. + // + ui32FIFOValue = AM_REG(ADC, FIFO); + + // + // Pop the FIFO. + // + AM_REG(ADC, FIFO) = 0; + + // + // Return FIFO valid bits. + // + return ui32FIFOValue; +} + +//***************************************************************************** +// +//! @brief Issue Software Trigger to the ADC. +//! +//! This function issues the software trigger to the ADC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_trigger(void) +{ + // + // Write to the Software trigger register in the ADC. + // + AM_REG(ADC, SWT) = 0x37; +} + +//***************************************************************************** +// +//! @brief Enable the ADC. +//! +//! Use this function to enable the ADC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_enable(void) +{ + // + // Enable the ADC. + // + AM_BFW(ADC, CFG, ADCEN, 0x1); +} + +//***************************************************************************** +// +//! @brief Disable the ADC. +//! +//! Use this function to disable the ADC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_disable(void) +{ + // + // Disable the ADC. + // + AM_BFW(ADC, CFG, ADCEN, 0x0); +} + +//***************************************************************************** +// +//! @brief Enable selected ADC Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h. +//! +//! Use this function to enable the ADC interrupts. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_int_enable(uint32_t ui32Interrupt) +{ + // + // Enable the interrupts. + // + AM_REG(ADC, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return enabled ADC Interrupts. +//! +//! Use this function to get all enabled ADC interrupts. +//! +//! @return enabled ADC Interrupts. +// +//***************************************************************************** +uint32_t +am_hal_adc_int_enable_get(void) +{ + // + // Return enabled interrupts. + // + return AM_REG(ADC, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable selected ADC Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h. +//! +//! Use this function to disable the ADC interrupts. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_int_disable(uint32_t ui32Interrupt) +{ + // + // Disable the interrupts. + // + AM_REG(ADC, INTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Clear selected ADC Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h. +//! +//! Use this function to clear the ADC interrupts. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_int_clear(uint32_t ui32Interrupt) +{ + // + // Clear the interrupts. + // + AM_REG(ADC, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Set selected ADC Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_adc.h. +//! +//! Use this function to set the ADC interrupts. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_adc_int_set(uint32_t ui32Interrupt) +{ + // + // Set the interrupts. + // + AM_REG(ADC, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return either enabled or raw selected ADC interrupt status. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! Use this function to get the ADC interrupt status. +//! +//! @return enabled or raw ADC interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_adc_int_status_get(bool bEnabledOnly) +{ + // + // Return the status. + // + if (bEnabledOnly) + { + uint32_t u32RetVal = AM_REG(ADC, INTEN); + u32RetVal &= AM_REG(ADC, INTSTAT); + return u32RetVal; + } + else + { + return AM_REG(ADC, INTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Return temperature in degrees C of supplied voltage. +//! +//! @param fVoltage - return the temperature corresponding to this voltage. +//! +//! Use this function to convert volts from the temperature sensor into degrees +//! C. Caller converts ADC binary code to volts based on reference used. +//! This routine looks up the trim parameters and returns corrected temperature. +//! +//! The computation is based on a line running through 0 degrees K. +//! We find the slope from the trimmed temperature calibration point. +//! +//! +//! @return the temperature in degrees C. +// +//***************************************************************************** +float +am_hal_adc_volts_to_celsius(float fVoltage) +{ + float fTemp; + + // + // Get calibration temperature from trimmed values & convert to degrees K. + // + float fCalibration_temp = priv_temp_trims.flt.fCalibrationTemperature; + + // + // Get remaining trimmed values. + // + float fCalibration_voltage = priv_temp_trims.flt.fCalibrationVoltage; + float fCalibration_offset = priv_temp_trims.flt.fCalibrationOffset; + + // + // Compute the temperature. + // + fTemp = fCalibration_temp; + fTemp /= (fCalibration_voltage - fCalibration_offset); + fTemp *= (fVoltage - fCalibration_offset); + + // + // Give it back to the caller in Celsius. + // + return fTemp - 273.15f; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_adc.h b/bsp/apollo2/libraries/drivers/hal/am_hal_adc.h new file mode 100644 index 0000000000..86b48b162c --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_adc.h @@ -0,0 +1,348 @@ +//***************************************************************************** +// +// am_hal_adc.h +//! @file +//! +//! @brief Functions for interfacing with the Analog to Digital Converter +//! +//! @addtogroup adc2 Analog-to-Digital Converter (ADC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_ADC_H +#define AM_HAL_ADC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name Clock Selection +//! @brief These macros may be used to set the ADC module's clock source. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_CLOCK_OFF AM_REG_ADC_CFG_CLKSEL_OFF +#define AM_HAL_ADC_CLOCK_HFRC AM_REG_ADC_CFG_CLKSEL_HFRC +#define AM_HAL_ADC_CLOCK_DIV2 AM_REG_ADC_CFG_CLKSEL_HFRC_DIV2 +//! @} + +//***************************************************************************** +// +//! @name Trigger Settings +//! @brief ADC trigger setting macros. +//! +//! These macros alter the ADC's trigger source and trigger polarity. Note that +//! the external trigger setting needs to be ORed with a POS or NEG option to +//! define the desired trigger polarity. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_TRIGGER_SOFT AM_REG_ADC_CFG_TRIGSEL_SWT +#define AM_HAL_ADC_TRIGGER_VCOMP AM_REG_ADC_CFG_TRIGSEL_VCOMP +#define AM_HAL_ADC_TRIGGER_EXT0 AM_REG_ADC_CFG_TRIGSEL_EXT0 +#define AM_HAL_ADC_TRIGGER_EXT1 AM_REG_ADC_CFG_TRIGSEL_EXT1 +#define AM_HAL_ADC_TRIGGER_EXT2 AM_REG_ADC_CFG_TRIGSEL_EXT2 +#define AM_HAL_ADC_TRIGGER_EXT3 AM_REG_ADC_CFG_TRIGSEL_EXT3 +#define AM_HAL_ADC_TRIGGER_FALL AM_REG_ADC_CFG_TRIGPOL_FALLING_EDGE +#define AM_HAL_ADC_TRIGGER_RISE AM_REG_ADC_CFG_TRIGPOL_RISING_EDGE +//! @} + +//***************************************************************************** +// +//! @name Reference Settings +//! @brief ADC reference voltage setting macros. +//! +//! These macros control the ADC reference voltage source. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_REF_EXT_2P0 AM_REG_ADC_CFG_REFSEL_EXT2P0 +#define AM_HAL_ADC_REF_EXT_1P5 AM_REG_ADC_CFG_REFSEL_EXT1P5 +#define AM_HAL_ADC_REF_INT_2P0 AM_REG_ADC_CFG_REFSEL_INT2P0 +#define AM_HAL_ADC_REF_INT_1P5 AM_REG_ADC_CFG_REFSEL_INT1P5 +//! @} + +//***************************************************************************** +// +//! @name Clock Mode +//! @brief ADC clock mode settings +//! +//! These macros determine whether the ADC shuts down its clock between +//! samples. Shutting down the clock will reduce power consumption, but +//! increase latency. This setting is only valid for LPMODE 0. For other modes, +//! it will be ignored. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_CK_LOW_POWER AM_REG_ADC_CFG_CKMODE_LPCKMODE +#define AM_HAL_ADC_CK_LOW_LATENCY AM_REG_ADC_CFG_CKMODE_LLCKMODE +//! @} + +//***************************************************************************** +// +//! @name Low Power Mode +//! @brief ADC power conservation settings. +//! +//! These macros select the power state to enter between active scans. Each low +//! power mode has its own set of timing constraints. Please see the datasheet +//! for additional timing information on each power mode. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_LPMODE_0 AM_REG_ADC_CFG_LPMODE_MODE0 +#define AM_HAL_ADC_LPMODE_1 AM_REG_ADC_CFG_LPMODE_MODE1 +//! @} + +//***************************************************************************** +// +//! @name Repeat Mode +//! @brief Enable repeating scan mode. +//! +//! Use this macro to enable repeating scans using timer 3. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_REPEAT AM_REG_ADC_CFG_RPTEN(1) +#define AM_HAL_ADC_NO_REPEAT AM_REG_ADC_CFG_RPTEN(0) +//! @} + +//***************************************************************************** +// +//! @name Slot configuration +//! @brief Slot configuration macros +//! +//! These macros may be used to configure an individual ADC slot. +//! @{ +// +//***************************************************************************** + +// Set number of samples to average. +#define AM_HAL_ADC_SLOT_AVG_1 AM_REG_ADC_SL0CFG_ADSEL0(0) +#define AM_HAL_ADC_SLOT_AVG_2 AM_REG_ADC_SL0CFG_ADSEL0(1) +#define AM_HAL_ADC_SLOT_AVG_4 AM_REG_ADC_SL0CFG_ADSEL0(2) +#define AM_HAL_ADC_SLOT_AVG_8 AM_REG_ADC_SL0CFG_ADSEL0(3) +#define AM_HAL_ADC_SLOT_AVG_16 AM_REG_ADC_SL0CFG_ADSEL0(4) +#define AM_HAL_ADC_SLOT_AVG_32 AM_REG_ADC_SL0CFG_ADSEL0(5) +#define AM_HAL_ADC_SLOT_AVG_64 AM_REG_ADC_SL0CFG_ADSEL0(6) +#define AM_HAL_ADC_SLOT_AVG_128 AM_REG_ADC_SL0CFG_ADSEL0(7) + +// Set slot precision mode. +#define AM_HAL_ADC_SLOT_14BIT AM_REG_ADC_SL0CFG_PRMODE0_P14B +#define AM_HAL_ADC_SLOT_12BIT AM_REG_ADC_SL0CFG_PRMODE0_P14B +#define AM_HAL_ADC_SLOT_10BIT AM_REG_ADC_SL0CFG_PRMODE0_P14B +#define AM_HAL_ADC_SLOT_8BIT AM_REG_ADC_SL0CFG_PRMODE0_P14B + +// Select a channel by number. +#define AM_HAL_ADC_SLOT_CHANNEL(n) AM_REG_ADC_SL0CFG_CHSEL0(n) + +// Single-ended channels +#define AM_HAL_ADC_SLOT_CHSEL_SE0 AM_REG_ADC_SL0CFG_CHSEL0_SE0 +#define AM_HAL_ADC_SLOT_CHSEL_SE1 AM_REG_ADC_SL0CFG_CHSEL0_SE1 +#define AM_HAL_ADC_SLOT_CHSEL_SE2 AM_REG_ADC_SL0CFG_CHSEL0_SE2 +#define AM_HAL_ADC_SLOT_CHSEL_SE3 AM_REG_ADC_SL0CFG_CHSEL0_SE3 +#define AM_HAL_ADC_SLOT_CHSEL_SE4 AM_REG_ADC_SL0CFG_CHSEL0_SE4 +#define AM_HAL_ADC_SLOT_CHSEL_SE5 AM_REG_ADC_SL0CFG_CHSEL0_SE5 +#define AM_HAL_ADC_SLOT_CHSEL_SE6 AM_REG_ADC_SL0CFG_CHSEL0_SE6 +#define AM_HAL_ADC_SLOT_CHSEL_SE7 AM_REG_ADC_SL0CFG_CHSEL0_SE7 +#define AM_HAL_ADC_SLOT_CHSEL_SE8 AM_REG_ADC_SL0CFG_CHSEL0_SE8 +#define AM_HAL_ADC_SLOT_CHSEL_SE9 AM_REG_ADC_SL0CFG_CHSEL0_SE9 + +// Differential channels. +#define AM_HAL_ADC_SLOT_CHSEL_DF0 AM_REG_ADC_SL0CFG_CHSEL0_DF0 +#define AM_HAL_ADC_SLOT_CHSEL_DF1 AM_REG_ADC_SL0CFG_CHSEL0_DF1 + +// Miscellaneous other signals. +#define AM_HAL_ADC_SLOT_CHSEL_TEMP AM_REG_ADC_SL0CFG_CHSEL0_TEMP +#define AM_HAL_ADC_SLOT_CHSEL_VSS AM_REG_ADC_SL0CFG_CHSEL0_VSS +#define AM_HAL_ADC_SLOT_CHSEL_VBATT AM_REG_ADC_SL0CFG_CHSEL0_BATT + +// Window enable. +#define AM_HAL_ADC_SLOT_WINDOW_EN AM_REG_ADC_SL0CFG_WCEN0(1) + +// Enable the slot. +#define AM_HAL_ADC_SLOT_ENABLE AM_REG_ADC_SL0CFG_SLEN0(1) +//! @} + +//***************************************************************************** +// +//! @name Interrupt Status Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to enable an individual ADC interrupt cause. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_INT_WCINC AM_REG_ADC_INTEN_WCINC(1) +#define AM_HAL_ADC_INT_WCEXC AM_REG_ADC_INTEN_WCEXC(1) +#define AM_HAL_ADC_INT_FIFOOVR2 AM_REG_ADC_INTEN_FIFOOVR2(1) +#define AM_HAL_ADC_INT_FIFOOVR1 AM_REG_ADC_INTEN_FIFOOVR1(1) +#define AM_HAL_ADC_INT_SCNCMP AM_REG_ADC_INTEN_SCNCMP(1) +#define AM_HAL_ADC_INT_CNVCMP AM_REG_ADC_INTEN_CNVCMP(1) +//! @} + +//***************************************************************************** +// +//! @name Temperature Trim Value Locations +//! @brief Temperature calibration cofficients are stored in readable space. +//! +//! These macros are used to access the temperature trim values in readable +//! space. +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_CALIB_TEMP_ADDR (0x50023010) +#define AM_HAL_ADC_CALIB_AMBIENT_ADDR (0x50023014) +#define AM_HAL_ADC_CALIB_ADC_OFFSET_ADDR (0x50023018) + +// +// Default coefficients (used when trims not provided): +// TEMP_DEFAULT = Temperature in deg K (e.g. 299.5 - 273.15 = 26.35) +// AMBIENT_DEFAULT = Voltage measurement at default temperature. +// OFFSET_DEFAULT = Default ADC offset at 1v. +// +#define AM_HAL_ADC_CALIB_TEMP_DEFAULT (299.5F) +#define AM_HAL_ADC_CALIB_AMBIENT_DEFAULT (1.02809F) +#define AM_HAL_ADC_CALIB_ADC_OFFSET_DEFAULT (-0.004281F) +//! @} + +//***************************************************************************** +// +//! @brief Configuration structure for the ADC. +// +//***************************************************************************** +typedef struct +{ + //! Select the ADC Clock source using one of the clock source macros. + uint32_t ui32Clock; + + //! Select the ADC trigger source using a trigger source macro. + uint32_t ui32TriggerConfig; + + //! Use a macro to select the ADC reference voltage. + uint32_t ui32Reference; + + //! Use a macro to decide whether to disable clocks between samples. + uint32_t ui32ClockMode; + + //! Use a macro to select the ADC power mode. + uint32_t ui32PowerMode; + + //! Select whether the ADC will re-trigger based on a signal from timer 3. + uint32_t ui32Repeat; +} +am_hal_adc_config_t; + +//***************************************************************************** +// +//! @brief ADC Fifo Read macros +//! +//! These are helper macros for interpreting FIFO data. Each ADC FIFO entry +//! contains information about the slot number and the FIFO depth alongside the +//! current sample. These macros perform the correct masking and shifting to +//! read those values. +//! +//! The SAMPLE and FULL_SAMPLE options refer to the fractional part of averaged +//! samples. If you are not using hardware averaging or don't need the +//! fractional part of the ADC sample, you should just use +//! AM_HAL_ADC_FIFO_SAMPLE. +//! +//! If you do need the fractional part, use AM_HAL_ADC_FIFO_FULL_SAMPLE. This +//! macro will keep six bits of precision past the decimal point. Depending on +//! the number of averaged samples, anywhere between 1 and 6 of these bits will +//! be valid. Please consult the datasheet to find out how many bits of data +//! are valid for your chosen averaging settings. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_ADC_FIFO_SAMPLE(value) \ + ((((value) & AM_REG_ADC_FIFO_DATA_M) >> AM_REG_ADC_FIFO_DATA_S) >> 6) + +#define AM_HAL_ADC_FIFO_FULL_SAMPLE(value) \ + (((value) & AM_REG_ADC_FIFO_DATA_M) >> AM_REG_ADC_FIFO_DATA_S ) + +#define AM_HAL_ADC_FIFO_SLOT(value) \ + (((value) & AM_REG_ADC_FIFO_SLOTNUM_M) >> AM_REG_ADC_FIFO_SLOTNUM_S) + +#define AM_HAL_ADC_FIFO_COUNT(value) \ + (((value) & AM_REG_ADC_FIFO_COUNT_M) >> AM_REG_ADC_FIFO_COUNT_S) +//! @} + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_adc_config(am_hal_adc_config_t *psConfig); +extern void am_hal_adc_window_set(uint32_t ui32Upper, uint32_t ui32Lower); +extern void am_hal_adc_slot_config(uint32_t ui32SlotNumber, + uint32_t ui32SlotConfig); + +extern uint32_t am_hal_adc_fifo_peek(void); +extern uint32_t am_hal_adc_fifo_pop(void); + +extern void am_hal_adc_trigger(void); +extern void am_hal_adc_enable(void); +extern void am_hal_adc_disable(void); +extern void am_hal_adc_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_adc_int_enable_get(void); +extern void am_hal_adc_int_disable(uint32_t ui32Interrupt); +extern void am_hal_adc_int_clear(uint32_t ui32Interrupt); +extern void am_hal_adc_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_adc_int_status_get(bool bEnabledOnly); +extern float am_hal_adc_volts_to_celsius(float fVoltage); +extern void am_hal_adc_temp_trims_get(float * pfTemp, float * pfVoltage, float * pfOffsetV); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_ADC_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.c b/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.c new file mode 100644 index 0000000000..23c7164418 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.c @@ -0,0 +1,576 @@ +//***************************************************************************** +// +// am_hal_cachectrl.c +//! @file +//! +//! @brief Functions for interfacing with the CACHE controller. +//! +//! @addtogroup clkgen2 Clock Generator (CACHE) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Default settings for the cache. +// +//***************************************************************************** +const am_hal_cachectrl_config_t am_hal_cachectrl_defaults = +{ + .ui32EnableCache = 1, + .ui32LRU = 0, + .ui32EnableNCregions = 0, + .ui32Config = AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_512, + .ui32SerialCacheMode = 0, + .ui32FlashCachingEnables = 3, + .ui32EnableCacheClockGating = 1, + .ui32EnableLightSleep = 0, + .ui32Dly = 1, + .ui32SMDly = 1, + .ui32EnableDataClockGating = 1, + .ui32EnableCacheMonitoring = 0, +}; + +//***************************************************************************** +// +//! @brief Enable the cache using the supplied settings +//! +//! @param psConfig - pointer to a config structure containing cache settings. +//! +//! This function takes in a structure of cache settings, and uses them to +//! enable the cache. This function will take care of the necessary register +//! writes both in this module and in the power control module, so a separate +//! powerctrl call is not necessary. +//! +//! For most applications, the default cache settings will be the most +//! efficient choice. To use the default cache settings with this function, use +//! the address of the global am_hal_cachectrl_defaults structure as the +//! psConfig argument. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_cachectrl_enable(const am_hal_cachectrl_config_t *psConfig) +{ + uint32_t ui32ConfigValue; + uint32_t ui32Timeout; + + // + // Pull the configuration data from the structure, and prepare to write the + // cache configuration register. + // + // NOTE: ICACHE and DCACHE settings were left out from this step. This is a + // workaround for a timing issue with early versions of Apollo2 that caused + // the cache to incorrectly mark itself valid during the startup sequence. + // The workaround calls for us to start the cache, manually invalidate it, + // and then enable ICACHE and DCACHE operation. + // + ui32ConfigValue = (AM_REG_CACHECTRL_CACHECFG_ENABLE( 1 ) | + AM_REG_CACHECTRL_CACHECFG_LRU( psConfig->ui32LRU ) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC0( (psConfig->ui32EnableNCregions & 0x1) >> 0 ) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC1( (psConfig->ui32EnableNCregions & 0x2) >> 1 ) | + psConfig->ui32Config | + AM_REG_CACHECTRL_CACHECFG_SERIAL(psConfig->ui32SerialCacheMode) | + AM_REG_CACHECTRL_CACHECFG_CACHE_CLKGATE( psConfig->ui32EnableCacheClockGating ) | + AM_REG_CACHECTRL_CACHECFG_CACHE_LS(psConfig->ui32EnableLightSleep ) | + AM_REG_CACHECTRL_CACHECFG_DLY( psConfig->ui32Dly ) | + AM_REG_CACHECTRL_CACHECFG_SMDLY( psConfig->ui32SMDly ) | + AM_REG_CACHECTRL_CACHECFG_DATA_CLKGATE(psConfig->ui32EnableDataClockGating) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_MONITOR(psConfig->ui32EnableCacheMonitoring) ); + + // + // Make sure the cache is enabled in the power control block. + // + am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEMEN_CACHE); + + // + // Set the initial cache settings. + // + AM_REG(CACHECTRL, CACHECFG) = ui32ConfigValue; + + // + // Wait for the cache ready signal. + // + for (ui32Timeout = 0; ui32Timeout < 50; ui32Timeout++) + { + if (AM_BFM(CACHECTRL, CACHECTRL, CACHE_READY)) + { + break; + } + } + + // + // Manually invalidate the cache (workaround for the issue described above.) + // + AM_BFW(CACHECTRL, CACHECTRL, INVALIDATE, 1); + + // + // Wait for the cache ready signal again. + // + for (ui32Timeout = 0; ui32Timeout < 50; ui32Timeout++) + { + if (AM_BFM(CACHECTRL, CACHECTRL, CACHE_READY)) + { + break; + } + } + + // + // Now that the cache is running, and correctly marked invalid, we can OR in + // the ICACHE and DCACHE settings. + // + ui32ConfigValue |= (AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE( (psConfig->ui32FlashCachingEnables & 0x1) >> 0 ) | + AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE( (psConfig->ui32FlashCachingEnables & 0x2) >> 1 ) ); + + // + // Write the final configuration settings to the CACHECTRL register. + // + AM_REG(CACHECTRL, CACHECFG) = ui32ConfigValue; +} + +//***************************************************************************** +// +//! @brief Disable the cache. +//! +//! Call this function to completely shut down cache features. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_cachectrl_disable(void) +{ + uint32_t ui32CacheCfg; + + // + // Save the cache settings. + // + ui32CacheCfg = AM_REG(CACHECTRL, CACHECFG); + + // + // Remove the ICACHE and DCACHE settings. + // + ui32CacheCfg &= (AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE(0) | + AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE(0)); + + // + // Write the resulting value back to the register. + // + AM_REG(CACHECTRL, CACHECFG) = ui32CacheCfg; + + // + // Read the CACHECTRL register a few times + // + AM_REG(CACHECTRL, CACHECTRL); + AM_REG(CACHECTRL, CACHECTRL); + AM_REG(CACHECTRL, CACHECTRL); + + // + // Disable the cache completely. + // + AM_BFW(CACHECTRL, CACHECFG, ENABLE, 0); + + // + // Power the cache down in the powerctrl block. + // + am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEMEN_CACHE_DIS); +} + +//***************************************************************************** +// +//! @brief Set a default cache configuration. +//! +//! This function is used to set a default cache configuration. +// +//***************************************************************************** +void +am_hal_cachectrl_config_default(void) +{ + // + // Set PWRCTRL + // + am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEMEN_CACHE); + + // + // Write a default configuration to the CACHECFG register. + // + AM_REG(CACHECTRL, CACHECFG) = \ + AM_REG_CACHECTRL_CACHECFG_ENABLE( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_LRU( 0 ) | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC0( 0 ) | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC1( 0 ) | \ + AM_REG_CACHECTRL_CACHECFG_CONFIG_W2_128B_512E | \ + AM_REG_CACHECTRL_CACHECFG_SERIAL( 0 ) | \ + AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_CACHE_CLKGATE( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_CACHE_LS( 0 ) | \ + AM_REG_CACHECTRL_CACHECFG_DLY( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_SMDLY( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_DATA_CLKGATE( 1 ) | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_MONITOR( 0 ); + + // + // Write a default configuration to the FLASHCFG register. + // + AM_REG(CACHECTRL, FLASHCFG) = AM_REG_CACHECTRL_FLASHCFG_RD_WAIT(1); + + // + // Write a default configuration to the CACHECTRL register. + // + AM_REG(CACHECTRL, CACHECTRL) = \ + AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_ENABLE(1) | \ + AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_DISABLE(0) | \ + AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_ENABLE(1) | \ + AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_DISABLE(0) | \ + AM_REG_CACHECTRL_CACHECTRL_RESET_STAT(0) | \ + AM_REG_CACHECTRL_CACHECTRL_INVALIDATE(0); + + // + // Write a default configuration to the NCR0START and NCR0END registers. + // + AM_REG(CACHECTRL, NCR0START) = \ + AM_REG_CACHECTRL_NCR0START_ADDR(0); + AM_REG(CACHECTRL, NCR0END) = \ + AM_REG_CACHECTRL_NCR0END_ADDR(0); + + // + // Write a default configuration to the NCR1START and NCR1END registers. + // + AM_REG(CACHECTRL, NCR1START) = \ + AM_REG_CACHECTRL_NCR1START_ADDR(0); + AM_REG(CACHECTRL, NCR1END) = \ + AM_REG_CACHECTRL_NCR1END_ADDR(0); + + // + // Write a default configuration to the DMONn and IMONn registers. + // + AM_REG(CACHECTRL, DMON0) = \ + AM_REG_CACHECTRL_DMON0_DACCESS_COUNT(0); + AM_REG(CACHECTRL, DMON1) = \ + AM_REG_CACHECTRL_DMON1_DLOOKUP_COUNT(0); + AM_REG(CACHECTRL, DMON2) = \ + AM_REG_CACHECTRL_DMON2_DHIT_COUNT(0); + AM_REG(CACHECTRL, DMON3) = \ + AM_REG_CACHECTRL_DMON3_DLINE_COUNT(0); + AM_REG(CACHECTRL, IMON0) = \ + AM_REG_CACHECTRL_IMON0_IACCESS_COUNT(0); + AM_REG(CACHECTRL, IMON1) = \ + AM_REG_CACHECTRL_IMON1_ILOOKUP_COUNT(0); + AM_REG(CACHECTRL, IMON2) = \ + AM_REG_CACHECTRL_IMON2_IHIT_COUNT(0); + AM_REG(CACHECTRL, IMON3) = \ + AM_REG_CACHECTRL_IMON3_ILINE_COUNT(0); +} + +//***************************************************************************** +// +//! @brief Enable the flash cache controller via a configuration structure. +//! +//! @param psConfig - Pointer to a data structure containing all of the data +// necessary to configure the CACHECFG register. +//! +//! This function is used to configure all fields of the CACHECFG. +// +//***************************************************************************** +void +am_hal_cachectrl_config(am_hal_cachectrl_config_t *psConfig) +{ + uint32_t u32ConfigValue; + + // + // Arrange all of the members of the data structure into a single u32 that + // can be written to the register. + // + u32ConfigValue = + AM_REG_CACHECTRL_CACHECFG_ENABLE( psConfig->ui32EnableCache ) | + AM_REG_CACHECTRL_CACHECFG_LRU( psConfig->ui32LRU ) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC0( + (psConfig->ui32EnableNCregions & 0x1) >> 0 ) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC1( + (psConfig->ui32EnableNCregions & 0x2) >> 1 ) | + psConfig->ui32Config | + AM_REG_CACHECTRL_CACHECFG_SERIAL(psConfig->ui32SerialCacheMode) | + AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE( + (psConfig->ui32FlashCachingEnables & 0x1) >> 0 ) | + AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE( + (psConfig->ui32FlashCachingEnables & 0x2) >> 1 ) | + AM_REG_CACHECTRL_CACHECFG_CACHE_CLKGATE( + psConfig->ui32EnableCacheClockGating ) | + AM_REG_CACHECTRL_CACHECFG_CACHE_LS( + psConfig->ui32EnableLightSleep ) | + AM_REG_CACHECTRL_CACHECFG_DLY( psConfig->ui32Dly ) | + AM_REG_CACHECTRL_CACHECFG_SMDLY( psConfig->ui32SMDly ) | + AM_REG_CACHECTRL_CACHECFG_DATA_CLKGATE( + psConfig->ui32EnableDataClockGating ) | + AM_REG_CACHECTRL_CACHECFG_ENABLE_MONITOR( + psConfig->ui32EnableCacheMonitoring ); + + // + // Write the configuration value to the CACHECFG register. + // + AM_REG(CACHECTRL, CACHECFG) = u32ConfigValue; +} + +//***************************************************************************** +// +//! @brief Configure the various flash cache controller enables. +//! +//! @param u32EnableMask - Mask of features to be enabled. +//! @param u32DisableMask - Mask of features to be disabled. +//! +//! This function is used to enable or disable the various flash cache +//! controller configuration enables which consist of the following: +//! AM_HAL_CACHECTRL_CACHECFG_ENABLE Flash cache controller +//! AM_HAL_CACHECTRL_CACHECFG_LRU_ENABLE LRU (disabled = LRR) +//! AM_HAL_CACHECTRL_CACHECFG_NC0_ENABLE Non-cacheable region 0 +//! AM_HAL_CACHECTRL_CACHECFG_NC1_ENABLE Non-cacheable region 1 +//! AM_HAL_CACHECTRL_CACHECFG_SERIAL_ENABLE Serial cache mode +//! AM_HAL_CACHECTRL_CACHECFG_ICACHE_ENABLE Instruction caching +//! AM_HAL_CACHECTRL_CACHECFG_DCACHE_ENABLE Data caching. +//! AM_HAL_CACHECTRL_CACHECFG_CACHE_CLKGATE_ENABLE Cache clock gating +//! AM_HAL_CACHECTRL_CACHECFG_LS_ENABLE Light sleep cache RAMs +//! AM_HAL_CACHECTRL_CACHECFG_DATA_CLKGATE_ENABLE Data clock gating +//! AM_HAL_CACHECTRL_CACHECFG_MONITOR_ENABLE Cache Monitoring Stats +//! +//! Note that if both an enable and disable are provided in their respective +//! masks, the enable will take precendence. +//! +//! @return The previous status of the flash cache controller enables. +// +//***************************************************************************** +#define CACHECTRL_VALID_ENABLES ( \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_M | \ + AM_REG_CACHECTRL_CACHECFG_LRU_M | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC0_M | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_NC1_M | \ + AM_REG_CACHECTRL_CACHECFG_SERIAL_M | \ + AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE_M | \ + AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE_M | \ + AM_REG_CACHECTRL_CACHECFG_CACHE_CLKGATE_M | \ + AM_REG_CACHECTRL_CACHECFG_CACHE_LS_M | \ + AM_REG_CACHECTRL_CACHECFG_DATA_CLKGATE_M | \ + AM_REG_CACHECTRL_CACHECFG_ENABLE_MONITOR_M ) + +uint32_t +am_hal_cachectrl_cache_enables(uint32_t u32EnableMask, uint32_t u32DisableMask) +{ + uint32_t ui32RetVal = AM_BFR(CACHECTRL, CACHECFG, ENABLE) & + CACHECTRL_VALID_ENABLES; + + // + // Make sure the enable masks include only valid bits. + // + u32EnableMask &= CACHECTRL_VALID_ENABLES; + u32DisableMask &= CACHECTRL_VALID_ENABLES; + + // + // First, do the disables. + // + AM_REG(CACHECTRL, CACHECFG) &= ~u32DisableMask; + + // + // Now set the enables. + // + AM_REG(CACHECTRL, CACHECFG) |= u32EnableMask; + + return ui32RetVal; +} + +//***************************************************************************** +// +//! @brief Select the cache configuration type. +//! +//! This functions only sets the CACHECFG CONFIG field. +//! +//! @param ui32CacheConfig - The cache configuration value. +//! +//! This function can be used to select the type of cache.frequency of the main +//! system clock. The ui32CacheConfig parameter should be set to one of the +//! following values: +//! +//! AM_HAL_CACHECTRL_CACHECFG_CONFIG_DIRECT_256 : Direct mapped, +//! 128-bit linesize, 256 entries (2 SRAMs active). +//! AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_256 : Two-way set associative, +//! 128-bit linesize, 256 entries (4 SRAMs active). +//! AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_512 : Two-way set associative, +//! 128-bit linesize, 512 entries (8 SRAMs active). +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_cachectrl_cache_config(uint32_t ui32CacheConfig) +{ + // + // Clear the bitfield + // + AM_REG(CACHECTRL, CACHECFG) &= ~AM_REG_CACHECTRL_CACHECFG_CONFIG_M; + + // + // Write the new value to the bitfield. + // + AM_REG(CACHECTRL, CACHECFG) |= ui32CacheConfig & + AM_REG_CACHECTRL_CACHECFG_CONFIG_M; +} + +//***************************************************************************** +// +//! @brief Invalidate the flash cache. +//! +//! This function is used to invalidate the flash cache. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_cachectrl_invalidate_flash_cache(void) +{ + // + // Write the bit to invalidate the flash cache. + // Note - this bit is not sticky, no need to write it back to 0. + // + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_INVALIDATE_GO; +} + +//***************************************************************************** +// +//! @brief Reset cache statistics. +//! +//! This function is used to reset cache statistics. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_cachectrl_reset_statistics(void) +{ + // + // Write the bit to reset flash statistics. + // Note - this bit is not sticky, no need to write it back to 0. + // + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_RESET_STAT_CLEAR; +} + +//***************************************************************************** +// +//! @brief Get flash cache sleep mode status. +//! +//! This function returns flash cache sleep mode statuses. +//! +//! @return +//! bit0 indicates that flash0 flash sleep mode is enabled. +//! bit1 indicates that flash1 flash sleep mode is enabled. +// +//***************************************************************************** +uint32_t +am_hal_cachectrl_sleep_mode_status(void) +{ + uint32_t ui32Status, ui32Ret; + + // + // Get the current sleep mode status bits. + // + ui32Status = AM_REG(CACHECTRL, CACHECTRL); + ui32Ret = (ui32Status & \ + AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_STATUS_M) >> \ + (AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_STATUS_S - 0); + ui32Ret |= (ui32Status & \ + AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_STATUS_M) >> \ + (AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_STATUS_S - 1); + + return ui32Ret; +} + +//***************************************************************************** +// +//! @brief Enable or disable flash cache sleep mode. +//! +//! This function enables or disables flash cache sleep mode. +//! @param ui32EnableMask - bit0 for flash0, bit1 for flash1. +//! @param ui32DisableMask - bit0 for flash0, bit1 for flash1. +//! +//! Note that if both an enable and disable are provided in their respective +//! masks, the enable will take precedence. +//! +//! @return Previous status. +//! bit0 indicates that flash0 flash sleep mode was previously enabled. +//! bit1 indicates that flash1 flash sleep mode was previously enabled. +// +//***************************************************************************** +uint32_t +am_hal_cachectrl_sleep_mode_enable(uint32_t ui32EnableMask, + uint32_t ui32DisableMask) +{ + uint32_t ui32Ret = am_hal_cachectrl_sleep_mode_status(); + + if ( ui32DisableMask & 0x1 ) + { + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_DISABLE_M; + } + + if ( ui32DisableMask & 0x2 ) + { + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_DISABLE_M; + } + + if ( ui32EnableMask & 0x1 ) + { + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_FLASH0_SLM_ENABLE_M; + } + + if ( ui32EnableMask & 0x2 ) + { + AM_REG(CACHECTRL, CACHECTRL) |= AM_REG_CACHECTRL_CACHECTRL_FLASH1_SLM_ENABLE_M; + } + + return ui32Ret; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.h b/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.h new file mode 100644 index 0000000000..b8ce914b94 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_cachectrl.h @@ -0,0 +1,211 @@ +//***************************************************************************** +// +// am_hal_cachectrl.h +//! @file +//! +//! @brief Functions for accessing and configuring the CACHE controller. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_CACHECTRL_H +#define AM_HAL_CACHECTRL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Cache configuration structure +// +//***************************************************************************** +typedef struct +{ + // + //! Set to 1 to enable the cache. + // + uint8_t ui32EnableCache; + + // + //! Set to 1 to enable the LRU cache replacement policy. + //! Set to 0 to enable the LRR (least recently used) replacement policy. + //! LEE minimizes writes to the TAG SRAM. + // + uint8_t ui32LRU; + + // + //! Set to 3 to enable non-cachable region 1 and non-cachable region 0. + //! Set to 2 to enable non-cachable region 1. + //! Set to 1 to enable non-cachable region 0. + //! Set to 0 to make all regions cacheable. + // + uint8_t ui32EnableNCregions; + + // + //! Set to: + //! AM_HAL_CACHECTRL_CACHECFG_CONFIG_DIRECT_256 for direct-mapped, + //! 128-bit linesize, 256 entries (2 SRAMs active) + //! AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_256 for two-way set associative, + //! 128-bit linesize, 256 entries (4 SRAMs active) + //! AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_512 for two-way set associative, + //! 128-bit linesize, 512 entries (8 SRAMs active) + // + uint8_t ui32Config; + + // + //! Set to 1 to enable serial cache mode. + // + uint8_t ui32SerialCacheMode; + + // + //! Set to 3 to enable flash data caching and flash instruction caching. + //! Set to 2 to enable flash data caching. + //! Set to 1 to enable flash instruction caching. + //! Set to 0 to disable flash data caching and flash instruction caching. + // + uint8_t ui32FlashCachingEnables; + + // + //! Set to 1 to enable clock gating of cache RAMs. + // + uint8_t ui32EnableCacheClockGating; + + // + //! Set to 1 to enable light sleep of cache RAMs. + // + uint8_t ui32EnableLightSleep; + + // + //! Set Data RAM delay value (0x0 - 0xF). + // + uint8_t ui32Dly; + + // + //! Set SM Data RAM delay value (0x0 - 0xF). + // + uint8_t ui32SMDly; + + // + //! Set to 1 to enable clock gating of the entire data array. + // + uint8_t ui32EnableDataClockGating; + + // + //! Set to 1 to enable cache monitor statistics. + // + uint8_t ui32EnableCacheMonitoring; +} +am_hal_cachectrl_config_t; + +extern const am_hal_cachectrl_config_t am_hal_cachectrl_defaults; + +//***************************************************************************** +// +//! @name Cache enables +//! @brief Configuration selection for the various cache enables. +//! +//! These macros may be used in conjunction with the +//! am_hal_cachectrl_cache_enable() function to enable various cache features. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_CACHECTRL_CACHECFG_ENABLE AM_REG_CACHECTRL_CACHECFG_ENABLE_M +#define AM_HAL_CACHECTRL_CACHECFG_LRU_ENABLE AM_REG_CACHECTRL_CACHECFG_LRU_M +#define AM_HAL_CACHECTRL_CACHECFG_NC0_ENABLE AM_REG_CACHECTRL_CACHECFG_ENABLE_NC0_M +#define AM_HAL_CACHECTRL_CACHECFG_NC1_ENABLE AM_REG_CACHECTRL_CACHECFG_ENABLE_NC1_M +#define AM_HAL_CACHECTRL_CACHECFG_SERIAL_ENABLE AM_REG_CACHECTRL_CACHECFG_SERIAL_M +#define AM_HAL_CACHECTRL_CACHECFG_ICACHE_ENABLE AM_REG_CACHECTRL_CACHECFG_ICACHE_ENABLE_M +#define AM_HAL_CACHECTRL_CACHECFG_DCACHE_ENABLE AM_REG_CACHECTRL_CACHECFG_DCACHE_ENABLE_M +#define AM_HAL_CACHECTRL_CACHECFG_CACHE_CLKGATE_ENABLE AM_REG_CACHECTRL_CACHECFG_CACHE_CLKGATE_M +#define AM_HAL_CACHECTRL_CACHECFG_LS_ENABLE AM_REG_CACHECTRL_CACHECFG_CACHE_LS_M +#define AM_HAL_CACHECTRL_CACHECFG_DATA_CLKGATE_ENABLE AM_REG_CACHECTRL_CACHECFG_DATA_CLKGATE_M +#define AM_HAL_CACHECTRL_CACHECFG_MONITOR_ENABLE AM_REG_CACHECTRL_CACHECFG_ENABLE_MONITOR_M +//! @} + +//***************************************************************************** +// +//! @name Cache Config +//! @brief Configuration selection for the cache. +//! +//! These macros may be used in conjunction with the +//! am_hal_cachectrl_cache_config() function to select the cache type. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_CACHECTRL_CACHECFG_CONFIG_DIRECT_256 AM_REG_CACHECTRL_CACHECFG_CONFIG_W1_128B_256E +#define AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_256 AM_REG_CACHECTRL_CACHECFG_CONFIG_W2_128B_256E +#define AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_512 AM_REG_CACHECTRL_CACHECFG_CONFIG_W2_128B_512E +//! @} + +//***************************************************************************** +// +// Default cache settings +// +//***************************************************************************** +#define AM_HAL_CACHECTRL_DEFAULTS \ + (AM_HAL_CACHECTRL_CACHECFG_ICACHE_ENABLE | \ + AM_HAL_CACHECTRL_CACHECFG_DCACHE_ENABLE | \ + AM_HAL_CACHECTRL_CACHECFG_CACHE_CLKGATE_ENABLE | \ + AM_HAL_CACHECTRL_CACHECFG_DATA_CLKGATE_ENABLE | \ + AM_HAL_CACHECTRL_CACHECFG_CONFIG_2WAY_512) + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_cachectrl_enable(const am_hal_cachectrl_config_t *psConfig); +extern void am_hal_cachectrl_disable(void); +extern void am_hal_cachectrl_config_default(void); +extern void am_hal_cachectrl_config(am_hal_cachectrl_config_t *psConfig); +extern uint32_t am_hal_cachectrl_cache_enables(uint32_t u32EnableMask, + uint32_t u32DisableMask); +extern void am_hal_cachectrl_cache_config(uint32_t ui32CacheConfig); +extern void am_hal_cachectrl_invalidate_flash_cache(void); +extern void am_hal_cachectrl_reset_statistics(void); +extern uint32_t am_hal_cachectrl_sleep_mode_status(void); +extern uint32_t am_hal_cachectrl_sleep_mode_enable(uint32_t ui32EnableMask, + uint32_t ui32DisableMask); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_CACHECTRL_H diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.c b/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.c new file mode 100644 index 0000000000..d60d7e47b5 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.c @@ -0,0 +1,491 @@ +//***************************************************************************** +// +// am_hal_clkgen.c +//! @file +//! +//! @brief Functions for interfacing with the CLKGEN. +//! +//! @addtogroup clkgen2 Clock Generator (CLKGEN) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// CLKGEN HFADJ register +// +//***************************************************************************** +#define AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT 0x5B8 + +//***************************************************************************** +// +//! @brief Select the clock divisor for the main system clock. +//! +//! @param ui32ClockSetting - The divisor value for the system clock. +//! +//! This function can be used to select the frequency of the main system clock. +//! The \e ui32ClockSetting parameter should be set to one of the following +//! values: +//! +//! AM_HAL_CLKGEN_SYSCLK_MAX +//! AM_HAL_CLKGEN_SYSCLK_48MHZ +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_sysclk_select(uint32_t ui32ClockSetting) +{ + am_hal_debug_assert_msg(ui32ClockSetting == AM_HAL_CLKGEN_SYSCLK_48MHZ, + "am_hal_clkgen_sysclk_select(): invalid clock setting."); + + // + // Unlock the clock control register. + // + AM_REG(CLKGEN, CLKKEY) = AM_REG_CLKGEN_CLKKEY_KEYVAL; + + // + // Set the HFRC divisor to the user-selected value. + // + AM_REG(CLKGEN, CCTRL) = ui32ClockSetting; + + // + // Lock the clock configuration registers. + // + AM_REG(CLKGEN, CLKKEY) = 0; +} + +//***************************************************************************** +// +//! @brief Get the current system clock frequency. +//! +//! This function can be used to determine the frequency of the main system +//! clock. The return value is the system clock frequency measured in hertz. +//! +//! @return System clock frequency in Hz +// +//***************************************************************************** +uint32_t +am_hal_clkgen_sysclk_get(void) +{ + uint32_t ui32ClockSetting; + + // + // Read the value of the clock divider. + // + ui32ClockSetting = AM_REG(CLKGEN, CCTRL) & AM_REG_CLKGEN_CCTRL_CORESEL_M; + + switch ( ui32ClockSetting ) + { + case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC: + return 48000000; + case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC_DIV2: + return 24000000; + default: + return 0xFFFFFFFF; + } +} + +//***************************************************************************** +// +//! @brief Enable selected CLKGEN Interrupts. +//! +//! Use this function to enable the interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h +//! +//! @return None +// +//***************************************************************************** +void +am_hal_clkgen_int_enable(uint32_t ui32Interrupt) +{ + // + // Enable the interrupts. + // + AM_REG(CLKGEN, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return enabled CLKGEN Interrupts. +//! +//! Use this function to get all enabled CLKGEN interrupts. +//! +//! @return enabled CLKGEN interrupts. +// +//***************************************************************************** +uint32_t +am_hal_clkgen_int_enable_get(void) +{ + // + // Return the enabled interrupts. + // + return AM_REG(CLKGEN, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable selected CLKGEN Interrupts. +//! +//! Use this function to disable the CLKGEN interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h +//! +//! @return None +// +//***************************************************************************** +void +am_hal_clkgen_int_disable(uint32_t ui32Interrupt) +{ + // + // Disable the interrupts. + // + AM_REG(CLKGEN, INTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Sets the interrupt status. +//! +//! @param ui32IntFlags interrupts to be enabled. +//! +//! This function sets the interrupts. +//! +//! Valid values for ui32IntFlags are: +//! +//! AM_HAL_CLKGEN_INT_RTC_ALARM +//! AM_HAL_CLKGEN_INT_XT_FAIL +//! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE +//! AM_HAL_CLKGEN_INT AUTOCAL_FAIL +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_int_set(uint32_t ui32Interrupt) +{ + // + // Set the interrupt status. + // + AM_REG(CLKGEN, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Gets the interrupt configuration. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! This function gets the currently configured interrupts. +//! +//! @return the configured interrupts. +//! +//! Possible values for the return are: +//! +//! AM_HAL_CLKGEN_INT_RTC_ALARM +//! AM_HAL_CLKGEN_INT_XT_FAIL +//! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE +//! AM_HAL_CLKGEN_INT AUTOCAL_FAIL +// +//***************************************************************************** +uint32_t +am_hal_clkgen_int_status_get(bool bEnabledOnly) +{ + // + // Return the status. + // + if ( bEnabledOnly ) + { + uint32_t u32RetVal = AM_REG(CLKGEN, INTSTAT); + u32RetVal &= AM_REG(CLKGEN, INTEN); + return u32RetVal; + } + else + { + return AM_REG(CLKGEN, INTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Clears the interrupts. +//! +//! @param ui32IntFlags interrupts to be cleared. +//! +//! This function clears the interrupts. +//! +//! Valid values for ui32IntFlags are: +//! +//! AM_HAL_CLKGEN_INT_RTC_ALARM +//! AM_HAL_CLKGEN_INT_XT_FAIL +//! AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE +//! AM_HAL_CLKGEN_INT AUTOCAL_FAIL +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_int_clear(uint32_t ui32Interrupt) +{ + // + // Clear the interrupts. + // + AM_REG(CLKGEN, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Starts the desired oscillator(s) (OSC). +//! +//! @param ui32OscFlags oscillator(s) to start. +//! +//! This function starts the desired oscillator(s) (OSC). +//! +//! Valid values for ui32OscFlags are: +//! +//! AM_HAL_CLKGEN_OSC_LFRC +//! AM_HAL_CLKGEN_OSC_XT +//! +//! @return 0 None. +// +//***************************************************************************** +void +am_hal_clkgen_osc_start(uint32_t ui32OscFlags) +{ + // + // Start the oscillator(s). + // + AM_REG(CLKGEN, OCTRL) &= ~ui32OscFlags; +} + +//***************************************************************************** +// +//! @brief Stops the desired oscillator(s) (OSC). +//! +//! @param ui32OscFlags oscillator(s) to stop. +//! +//! This function stops the desired oscillator(s) (OSC). +//! +//! Valid values for ui32OscFlags are: +//! +//! AM_HAL_CLKGEN_OSC_LFRC +//! AM_HAL_CLKGEN_OSC_XT +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_osc_stop(uint32_t ui32OscFlags) +{ + // + // Stop the oscillator(s). + // + AM_REG(CLKGEN, OCTRL) |= ui32OscFlags; +} + +//***************************************************************************** +// +//! @brief Enables the clock out signal. +//! +//! @param ui32Signal desired location for the clock out signal. +//! +//! This function enables the clock out signal. See am_hal_clkgen.h for +//! available signals. +//! +//! e.g. AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC +//! AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV4 +//! AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_clkout_enable(uint32_t ui32Signal) +{ + // + // Enable the clock out on desired signal. + // + AM_REG(CLKGEN, CLKOUT) = AM_REG_CLKGEN_CLKOUT_CKEN_M | ui32Signal; +} + +//***************************************************************************** +// +//! @brief Disables the clock out signal. +//! +//! This function disables the clock out signal. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_clkout_disable(void) +{ + // + // Disable the clock out. + // + AM_REG(CLKGEN, CLKOUT) = 0; +} + +//***************************************************************************** +// +//! @brief Enable UART system clock. +//! +//! This function enables or disables the UART system clock. +//! +//! @param ui32Module is 0 or 1 for Apollo2. +//! @param ui32UartEn is one of the following. +//! AM_HAL_CLKGEN_UARTEN_DIS +//! AM_HAL_CLKGEN_UARTEN_EN +//! AM_HAL_CLKGEN_UARTEN_REDUCE_FREQ +//! AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_uarten_set(uint32_t ui32Module, uint32_t ui32UartEn) +{ + uint32_t ui32Mask; + + if ( (ui32Module >= AM_REG_UART_NUM_MODULES) || + (ui32UartEn > AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV) ) + { + return; + } + + ui32UartEn <<= (ui32Module * AM_HAL_CLKGEN_UARTEN_UARTENn_S(ui32Module)); + ui32Mask = ~(AM_HAL_CLKGEN_UARTEN_UARTENn_M(ui32Module)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Set the UART clock + // + AM_REG(CLKGEN, UARTEN) &= ui32Mask; + AM_REG(CLKGEN, UARTEN) |= ui32UartEn; + + // + // Begin critical section. + // + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +//! @brief Enables HFRC auto-adjustment at the specified interval. +//! +//! @param ui32Warmup - How long to give the HFRC to stabilize during each +//! calibration attempt. +//! @param ui32Frequency - How often the auto-adjustment should happen. +//! +//! This function enables HFRC auto-adjustment from an external crystal +//! oscillator even when the crystal is not normally being used. +//! +//! ui32Warmup should be one of the following values: +//! +//! AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC +//! AM_REG_CLKGEN_HFADJ_HFWARMUP_2SEC +//! +//! ui32Frequency should be one of the following values: +//! +//! AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_16SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_32SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_64SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_128SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_256SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_512SEC +//! AM_REG_CLKGEN_HFADJ_HFADJCK_1024SEC +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_hfrc_adjust_enable(uint32_t ui32Warmup, uint32_t ui32Frequency) +{ + // + // Set the HFRC Auto-adjust register for the user's chosen settings. Assume + // that the HFRC should be calibrated to 48 MHz and that the crystal is + // running at 32.768 kHz. + // + AM_REG(CLKGEN, HFADJ) = + AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2 | + ui32Warmup | + AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT) | + ui32Frequency | + AM_REG_CLKGEN_HFADJ_HFADJEN_EN; +} + +//***************************************************************************** +// +//! @brief Disables HFRC auto-adjustment. +//! +//! This function disables HFRC auto-adjustment. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_clkgen_hfrc_adjust_disable(void) +{ + // + // Disable the clock out. + // + AM_REG(CLKGEN, HFADJ) = + AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2 | + AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC | + AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT) | + AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC | + AM_REG_CLKGEN_HFADJ_HFADJEN_DIS; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.h b/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.h new file mode 100644 index 0000000000..fc50cb9b43 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_clkgen.h @@ -0,0 +1,206 @@ +//***************************************************************************** +// +// am_hal_clkgen.h +//! @file +//! +//! @brief Functions for accessing and configuring the CLKGEN. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_CLKGEN_H +#define AM_HAL_CLKGEN_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name System Clock max frequency +//! @brief Defines the maximum clock frequency for this device. +//! +//! These macros provide a definition of the maximum clock frequency. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_CLKGEN_FREQ_MAX_HZ 48000000 +#define AM_HAL_CLKGEN_FREQ_MAX_MHZ (AM_HAL_CLKGEN_FREQ_MAX_HZ / 1000000) +//! @} + +//***************************************************************************** +// +//! @name System Clock Selection +//! @brief Divisor selection for the main system clock. +//! +//! These macros may be used along with the am_hal_clkgen_sysctl_select() +//! function to select the frequency of the main system clock. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_CLKGEN_SYSCLK_MAX AM_REG_CLKGEN_CCTRL_CORESEL_HFRC +#define AM_HAL_CLKGEN_SYSCLK_48MHZ AM_REG_CLKGEN_CCTRL_CORESEL_HFRC +//! @} + +//***************************************************************************** +// +//! @name Interrupt Status Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to set and clear interrupt bits. +//! @{ +// +//***************************************************************************** +#define AM_HAL_CLKGEN_INT_ALM AM_REG_CLKGEN_INTEN_ALM_M +#define AM_HAL_CLKGEN_INT_OF AM_REG_CLKGEN_INTEN_OF_M +#define AM_HAL_CLKGEN_INT_ACC AM_REG_CLKGEN_INTEN_ACC_M +#define AM_HAL_CLKGEN_INT_ACF AM_REG_CLKGEN_INTEN_ACF_M +//! @} + +//***************************************************************************** +// +//! @name OSC Start and Stop +//! @brief OSC Start and Stop defines. +//! +//! OSC Start and Stop defines to be used with \e am_hal_clkgen_osc_x(). +//! @{ +// +//***************************************************************************** +#define AM_HAL_CLKGEN_OSC_LFRC AM_REG_CLKGEN_OCTRL_STOPRC_M +#define AM_HAL_CLKGEN_OSC_XT AM_REG_CLKGEN_OCTRL_STOPXT_M +//! @} + +//***************************************************************************** +// +// OSC Start, Stop, Select defines +// +//***************************************************************************** +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV2 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV2 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV4 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV4 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV8 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV8 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV16 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV16 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV32 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV32 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_RTC_100Hz AM_REG_CLKGEN_CLKOUT_CKSEL_RTC_100Hz +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV2M AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV2M +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT AM_REG_CLKGEN_CLKOUT_CKSEL_XT +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_CG_100Hz AM_REG_CLKGEN_CLKOUT_CKSEL_CG_100Hz +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV4 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV4 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV8 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV8 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV32 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV32 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV64 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV64 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV128 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV128 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV256 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV256 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_CORE_CLK AM_REG_CLKGEN_CLKOUT_CKSEL_CORE_CLK +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_FLASH_CLK AM_REG_CLKGEN_CLKOUT_CKSEL_FLASH_CLK +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC_DIV2 AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC_DIV2 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC_DIV32 AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC_DIV32 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC_DIV512 AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC_DIV512 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC_DIV32K AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC_DIV32K +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV256 AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV256 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV8K AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV8K +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XT_DIV64K AM_REG_CLKGEN_CLKOUT_CKSEL_XT_DIV64K +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV16 AM_REG_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV16 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV128 AM_REG_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV128 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_ULFRC_1Hz AM_REG_CLKGEN_CLKOUT_CKSEL_ULFRC_1Hz +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV4K AM_REG_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV4K +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV1M AM_REG_CLKGEN_CLKOUT_CKSEL_ULFRC_DIV1M +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV64K AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV64K +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV16M AM_REG_CLKGEN_CLKOUT_CKSEL_HFRC_DIV16M +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC_DIV2M AM_REG_CLKGEN_CLKOUT_CKSEL_LFRC_DIV2M +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRCNE AM_REG_CLKGEN_CLKOUT_CKSEL_HFRCNE +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRCNE_DIV8 AM_REG_CLKGEN_CLKOUT_CKSEL_HFRCNE_DIV8 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_CORE_CLKNE AM_REG_CLKGEN_CLKOUT_CKSEL_CORE_CLKNE +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XTNE AM_REG_CLKGEN_CLKOUT_CKSEL_XTNE +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_XTNE_DIV16 AM_REG_CLKGEN_CLKOUT_CKSEL_XTNE_DIV16 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRCNE_DIV32 AM_REG_CLKGEN_CLKOUT_CKSEL_LFRCNE_DIV32 +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_FCLKNE AM_REG_CLKGEN_CLKOUT_CKSEL_FCLKNE +#define AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRCNE AM_REG_CLKGEN_CLKOUT_CKSEL_LFRCNE + +//***************************************************************************** +// +// UARTEN +// +//***************************************************************************** +#define AM_HAL_CLKGEN_UARTEN_DIS AM_REG_CLKGEN_UARTEN_UART0EN_DIS +#define AM_HAL_CLKGEN_UARTEN_EN AM_REG_CLKGEN_UARTEN_UART0EN_EN +#define AM_HAL_CLKGEN_UARTEN_REDUCE_FREQ AM_REG_CLKGEN_UARTEN_UART0EN_REDUCE_FREQ +#define AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV AM_REG_CLKGEN_UARTEN_UART0EN_EN_POWER_SAV + +#define AM_HAL_CLKGEN_UARTEN_UARTENn_S(module) \ + ((module) * \ + (AM_REG_CLKGEN_UARTEN_UART1EN_S - AM_REG_CLKGEN_UARTEN_UART0EN_S)) + +#define AM_HAL_CLKGEN_UARTEN_UARTENn_M(module) \ + (AM_REG_CLKGEN_UARTEN_UART0EN_M << AM_HAL_CLKGEN_UARTEN_UARTENn_S(module)) + +// +// UARTEN: entype is one of DIS, EN, REDUCE_FREQ, EN_POWER_SAV. +// +#define AM_HAL_CLKGEN_UARTEN_UARTENn(module, entype) \ + (AM_REG_CLKGEN_UARTEN_UART0EN_##entype << \ + AM_HAL_CLKGEN_UARTEN_UARTENn_S(module)) + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_clkgen_sysclk_select(uint32_t ui32ClockSetting); +extern uint32_t am_hal_clkgen_sysclk_get(void); +extern void am_hal_clkgen_osc_start(uint32_t ui32OscFlags); +extern void am_hal_clkgen_osc_stop(uint32_t ui32OscFlags); +extern void am_hal_clkgen_clkout_enable(uint32_t ui32Signal); +extern void am_hal_clkgen_clkout_disable(void); +extern void am_hal_clkgen_uarten_set(uint32_t ui32Module, uint32_t ui32UartEn); +extern void am_hal_clkgen_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_clkgen_int_enable_get(void); +extern void am_hal_clkgen_int_disable(uint32_t ui32Interrupt); +extern void am_hal_clkgen_int_clear(uint32_t ui32Interrupt); +extern void am_hal_clkgen_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_clkgen_int_status_get(bool bEnabledOnly); +extern void am_hal_clkgen_hfrc_adjust_enable(uint32_t ui32Warmup, uint32_t ui32Frequency); +extern void am_hal_clkgen_hfrc_adjust_disable(void); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_CLKGEN_H diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.c b/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.c new file mode 100644 index 0000000000..13fc3c07cc --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.c @@ -0,0 +1,1687 @@ +//***************************************************************************** +// +// am_hal_ctimer.c +//! @file +//! +//! @brief Functions for interfacing with the Counter/Timer module. +//! +//! @addtogroup ctimer2 Counter/Timer (CTIMER) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Address space distance between timer configuration registers. +// +//***************************************************************************** +#define MAX_CTIMERS 4 +#define TIMER_OFFSET (AM_REG_CTIMER_TMR1_O - AM_REG_CTIMER_TMR0_O) +#define CTIMER_CMPR_OFFSET (AM_REG_CTIMER_CMPRB0_O - AM_REG_CTIMER_CMPRA0_O) + +//***************************************************************************** +// +// Adjacency check +// +// This is related to the timer read workaround. This macro checks to see if +// the two supplied count values are within one "tick" of eachother. It should +// still pass in the event of a timer rollover. +// +//***************************************************************************** +#define adjacent(A, B) (((A) == (B)) || (((A) + 1) == (B)) || ((B) == 0)) + +//***************************************************************************** +// +// Array of function pointers for handling CTimer interrupts. +// +//***************************************************************************** +am_hal_ctimer_handler_t am_hal_ctimer_ppfnHandlers[16]; + +//***************************************************************************** +// +// Static function for reading the timer value. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +__attribute__((naked)) +static +void +back2back_reads(uint32_t u32TimerAddr, uint32_t u32Data[]) +{ + // u32TimerAddr = address of the timer to be read. + // u32Data[] is a pointer to a 3 word data array provided by the caller. + __asm + ( + // Do 3 back-to-back reads of the register + " push {r4}\n" // Save r4 + " push {r1}\n" // Save the data array ptr for later + " mov r2, r0\n" // Get Timer Addr + " mrs r4, PRIMASK\n" // Save PRIMASK + " cpsid i\n" // __disable_irq() + " nop\n" // Give the disable a cycle to take affect (but almost certainly not really needed) + " ldr r0, [r2, #0]\n" // Get TMRn register value + " ldr r1, [r2, #0]\n" // Get TMRn register value again + " ldr r3, [r2, #0]\n" // Get TMRn register value for a third time + " msr PRIMASK, r4\n" // Restore PRIMASK + " pop {r2}\n" // Get the array ptr + " str r0, [r2, #0]\n" // Store register value to variable + " str r1, [r2, #4]\n" // Store register value to variable + " str r3, [r2, #8]\n" // Store register value to variable + " pop {r4}\n" // restore r4 + " bx lr\n" + ); +} + +#elif defined(__ARMCC_VERSION) +__asm static uint32_t +back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[]) +{ + push {r4} // Save r4 + push {r1} // Save the data array ptr for later + mov r2, r0 // Get Timer Addr + mrs r4, PRIMASK // Save PRIMASK + cpsid i // __disable_irq() + nop // Give the disable a cycle to take affect (but almost certainly not really needed) + ldr r0, [r2, #0] // Get TMRn register value + ldr r1, [r2, #0] // Get TMRn register value again + ldr r3, [r2, #0] // Get TMRn register value for a third time + msr PRIMASK, r4 // Restore PRIMASK + pop {r2} // Get the array ptr + str r0, [r2, #0] // Store register value to variable + str r1, [r2, #4] // Store register value to variable + str r3, [r2, #8] // Store register value to variable + pop {r4} // Restore r4 + bx lr +} + +#elif defined(__IAR_SYSTEMS_ICC__) +#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing + // return statement on a non-void function +__stackless static uint32_t +back2back_reads( uint32_t u32TimerAddr, uint32_t u32Data[]) +{ + __asm(" push {r4}"); // Save r4 + __asm(" push {r1}"); // Save the data array ptr for later + __asm(" mov r2, r0"); // Get Timer Addr + __asm(" mrs r4, PRIMASK"); // Save PRIMASK" + __asm(" cpsid i"); // __disable_irq() + __asm(" nop"); // Give the disable a cycle to take affect (but almost certainly not really needed) + __asm(" ldr r0, [r2, #0]"); // Get TMRn register value + __asm(" ldr r1, [r2, #0]"); // Get TMRn register value again + __asm(" ldr r3, [r2, #0]"); // Get TMRn register value for a third time + __asm(" msr PRIMASK, r4"); // Restore PRIMASK + __asm(" pop {r2}"); // Get the array ptr + __asm(" str r0, [r2, #0]"); // Store register value to variable + __asm(" str r1, [r2, #4]"); // Store register value to variable + __asm(" str r3, [r2, #8]"); // Store register value to variable + __asm(" pop {r4}"); // Restore r4 + __asm(" bx lr"); +} +#pragma diag_default = Pe940 // Restore IAR compiler warning +#endif + +//***************************************************************************** +// +// @brief Check to see if the given CTimer is using the HFRC +// +// Note - Calls to this function should be from inside a critical section. +// +//! @return None. +// +//***************************************************************************** +static bool +ctimer_source_hfrc(uint32_t ui32CtimerNum) +{ + uint32_t *pui32ConfigReg; + uint32_t ui32TimerASrc, ui32TimerBSrc; + + // + // Find the correct register to write. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32CtimerNum * TIMER_OFFSET)); + + // + // Determine if this timer is using HFRC as the clock source. + // The value we are looking for is HFRC_DIV4 to HFRC_DIV4K. + // Get the clock sources and 0-base the extracted value. + // + ui32TimerASrc = AM_BFX(CTIMER, CTRL0, TMRA0CLK, *pui32ConfigReg) - + AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4); + ui32TimerBSrc = AM_BFX(CTIMER, CTRL0, TMRB0CLK, *pui32ConfigReg) - + AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4); + + // + // If the source value is 0 to (HFRC_DIV4K - HFRC_DIV4), then it's HFRC. + // + if ( (ui32TimerASrc <= (AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4K) - + AM_ENUMX(CTIMER, CTRL0, TMRA0CLK, HFRC_DIV4))) || + (ui32TimerBSrc <= (AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4K) - + AM_ENUMX(CTIMER, CTRL0, TMRB0CLK, HFRC_DIV4))) ) + { + return true; + } + else + { + return false; + } + +} // ctimer_source_hfrc() + +//***************************************************************************** +// +// @brief Check to see if any of the CTimers or STimer are using the HFRC. +// +// This function should be used to check if the HFRC is being used in order +// to correctly establish power related settings. +// +// Note - Calls to this function should be from inside a critical section. +// +//! @return None. +// +//***************************************************************************** +static bool +timers_use_hfrc(void) +{ + uint32_t ui32TimerASrc, ui32CtimerNum; + + // + // Check STimer to see if it is using HFRC. + // + ui32TimerASrc = AM_BFR(CTIMER, STCFG, CLKSEL); + if ( (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) || + (ui32TimerASrc == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) ) + { + return true; + } + + // + // Check the CTimers to see if any are using HFRC as their clock source. + // + for ( ui32CtimerNum = 0; ui32CtimerNum < MAX_CTIMERS; ui32CtimerNum++ ) + { + if ( ctimer_source_hfrc(ui32CtimerNum) ) + { + return true; + } + } + + return false; + +} // timers_use_hfrc() + +//***************************************************************************** +// +//! @brief Convenience function for responding to CTimer interrupts. +//! +//! @param ui32Status is the interrupt status as returned by +//! am_hal_ctimer_int_status_get() +//! +//! This function may be called from am_ctimer_isr() to read the status of +//! the CTimer interrupts, determine which source caused the most recent +//! interrupt, and call an interrupt handler function to respond. The interrupt +//! handler to be called must be first registered with the +//! am_hal_ctimer_int_register() function. +//! +//! In the event that multiple sources are active, the corresponding +//! interrupt handlers will be called in numerical order based on interrupt def. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_service(uint32_t ui32Status) +{ + uint32_t ui32Clz; + + am_hal_ctimer_handler_t pfnHandler; + + ui32Status &= 0xFFFF; + + while ( ui32Status ) + { + // + // Pick one of any remaining active interrupt bits + // +#ifdef __IAR_SYSTEMS_ICC__ + ui32Clz = __CLZ(ui32Status); +#else + ui32Clz = __builtin_clz(ui32Status); +#endif + + // + // Turn off the bit we picked in the working copy + // + ui32Status &= ~(0x80000000 >> ui32Clz); + + // + // Check the bit handler table to see if there is an interrupt handler + // registered for this particular bit. + // + pfnHandler = am_hal_ctimer_ppfnHandlers[31 - ui32Clz]; + if ( pfnHandler ) + { + // + // If we found an interrupt handler routine, call it now. + // + pfnHandler(); + } + } +} // am_hal_ctimer_int_service() + +//***************************************************************************** +// +//! @brief Register an interrupt handler for CTimer. +//! +//! @param ui32Interrupt - interrupt number to assign this interrupt handler to. +//! @param pfnHandler - Function to call when this interrupt is received. +//! +//! This function allows the caller to specify a function that should be called +//! any time a Ctimer interrupt is received. Registering an +//! interrupt handler using this function adds the function pointer to an array +//! in SRAM. This interrupt handler will be called by am_hal_ctimer_int_service() +//! whenever the ui32Status parameter indicates that the corresponding interrupt. +//! +//! To remove an interrupt handler that has already been registered, the +//! pfnHandler parameter may be set to zero. +//! +//! @note This function will not have any effect unless the +//! am_hal_ctimer_int_service() function is being used. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_register(uint32_t ui32Interrupt, + am_hal_ctimer_handler_t pfnHandler) +{ + uint32_t intIdx = 0; + + // + // Check to make sure the interrupt number is valid. (Debug builds only) + // + switch (ui32Interrupt) + { + case AM_REG_CTIMER_INTEN_CTMRA0C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA0C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB0C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB0C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA1C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA1C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB1C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB1C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA2C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA2C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB2C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB2C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA3C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA3C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB3C0INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB3C0INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA0C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA0C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB0C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB0C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA1C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA1C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB1C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB1C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA2C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA2C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB2C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB2C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRA3C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRA3C1INT_S; + break; + + case AM_REG_CTIMER_INTEN_CTMRB3C1INT_M: + intIdx = AM_REG_CTIMER_INTEN_CTMRB3C1INT_S; + break; + + default: + am_hal_debug_assert_msg(false, "CTimer interrupt number out of range."); + } + + am_hal_ctimer_ppfnHandlers[intIdx] = pfnHandler; + +} // am_hal_ctimer_int_register() + +//***************************************************************************** +// +//! @brief Set up the counter/timer. +//! +//! @param ui32TimerNumber is the number of the Timer that should be +//! configured. +//! +//! @param psConfig is a pointer to a structure that holds important settings +//! for the timer. +//! +//! This function should be used to perform the initial set-up of the +//! counter-timer. +//! +//! @note This function will eventually be replaced by +//! am_hal_ctimer_config_single(), which performs the same configuration +//! without requiring a structure. Please use am_hal_ctimer_config_single() for +//! new development. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_config(uint32_t ui32TimerNumber, + am_hal_ctimer_config_t *psConfig) +{ + uint32_t *pui32ConfigReg; + uint32_t ui32ConfigVal; + + // + // Start preparing the configuration word for this timer. The configuration + // values for Timer A and Timer B provided in the config structure should + // match the register definitions already, so we will mostly just need to + // OR them together. + // + ui32ConfigVal = ( (psConfig->ui32TimerAConfig) | + (psConfig->ui32TimerBConfig << 16) ); + + // + // OR in the Link bit if the timers need to be linked. + // + ui32ConfigVal |= psConfig->ui32Link ? AM_HAL_CTIMER_LINK : 0; + + // + // Begin critical section while config registers are read and modified. + // + AM_CRITICAL_BEGIN_ASM + + // + // Find the correct register to write. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Write our configuration value. + // + AM_REGVAL(pui32ConfigReg) = ui32ConfigVal; + + // + // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled. + // + if ( timers_use_hfrc() ) + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0); + } + else + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1); + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM + +} // am_hal_ctimer_config() + +//***************************************************************************** +// +//! @brief Set up the counter/timer. +//! +//! @param ui32TimerNumber is the number of the Timer that should be +//! configured. +//! +//! @param ui32TimerSegment specifies which segment of the timer should be +//! enabled. +//! +//! @param ui32Configval specifies the configuration options for the selected +//! timer. +//! +//! This function should be used to perform the initial set-up of the +//! counter-timer. It can be used to configure either a 16-bit timer (A or B) or a +//! 32-bit timer using the BOTH option. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! The timer's clock source, mode, interrupt, and external pin behavior are +//! all controlled through the \e ui32Configval parameter. The valid options +//! for ui32ConfigVal include any ORed together combination of the following: +//! +//! Clock configuration macros: +//! +//! AM_HAL_CTIMER_HFRC_24MHZ +//! AM_HAL_CTIMER_LFRC_512HZ +//! ... etc. (See am_hal_ctimer.h for the full set of options.) +//! +//! Mode selection macros: +//! +//! AM_HAL_CTIMER_FN_ONCE +//! AM_HAL_CTIMER_FN_REPEAT +//! AM_HAL_CTIMER_FN_PWM_ONCE +//! AM_HAL_CTIMER_FN_PWM_REPEAT +//! AM_HAL_CTIMER_FN_CONTINUOUS +//! +//! Interrupt control: +//! +//! AM_HAL_CTIMER_INT_ENABLE +//! +//! Pin control: +//! +//! AM_HAL_CTIMER_PIN_ENABLE +//! AM_HAL_CTIMER_PIN_INVERT +//! +//! ADC trigger (Timer 3 only): +//! +//! AM_HAL_CTIMER_ADC_TRIG +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_config_single(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment, + uint32_t ui32ConfigVal) +{ + volatile uint32_t *pui32ConfigReg; + uint32_t ui32WriteVal; + + // + // Find the correct register to write based on the timer number. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section while config registers are read and modified. + // + AM_CRITICAL_BEGIN_ASM + + // + // Save the value that's already in the register. + // + ui32WriteVal = AM_REGVAL(pui32ConfigReg); + + // + // If we're working with TIMERB, we need to shift our configuration value + // up by 16 bits. + // + + if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB ) + { + ui32ConfigVal = ((ui32ConfigVal & 0xFFFF) << 16); + } + + // + // Replace part of the saved register value with the configuration value + // from the caller. + // + ui32WriteVal = (ui32WriteVal & ~(ui32TimerSegment)) | ui32ConfigVal; + + // + // If we're configuring both timers, we need to set the "link" bit. + // + if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH ) + { + ui32WriteVal |= AM_HAL_CTIMER_LINK; + } + + // + // Write our completed configuration value. + // + AM_REGVAL(pui32ConfigReg) = ui32WriteVal; + + // + // If all of the clock sources are not HRFC disable LDO when sleeping if timers are enabled. + // + if ( timers_use_hfrc() ) + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0); + } + else + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1); + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM + +} // am_hal_ctimer_config_single() + +//***************************************************************************** +// +//! @brief Start a timer +//! +//! @param ui32TimerNumber is the number of the timer to enable +//! +//! @param ui32TimerSegment specifies which segment of the timer should be +//! enabled. Valid values for ui32TimerSegment are: +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! This function will enable a timer to begin incrementing. The \e +//! ui32TimerNumber parameter selects the timer that should be enabled, for +//! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows +//! the caller to individually select a segment within a timer to be enabled, +//! such as TIMER0A, TIMER0B, or both. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_start(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t *pui32ConfigReg; + uint32_t ui32ConfigVal; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section while config registers are read and modified. + // + AM_CRITICAL_BEGIN_ASM + + // + // Read the current value. + // + ui32ConfigVal = *pui32ConfigReg; + + // + // Clear out the "clear" bit. + // + ui32ConfigVal &= ~(ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0CLR_M | + AM_REG_CTIMER_CTRL0_TMRB0CLR_M)); + + // + // Set the "enable bit" + // + ui32ConfigVal |= (ui32TimerSegment & (AM_REG_CTIMER_CTRL0_TMRA0EN_M | + AM_REG_CTIMER_CTRL0_TMRB0EN_M)); + + // + // Write the value back to the register. + // + AM_REGVAL(pui32ConfigReg) = ui32ConfigVal; + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_start() + +//***************************************************************************** +// +//! @brief Stop a timer +//! +//! @param ui32TimerNumber is the number of the timer to disable. +//! +//! @param ui32TimerSegment specifies which segment of the timer should be +//! disabled. +//! +//! This function will stop the selected timer from incrementing. The \e +//! ui32TimerNumber parameter selects the timer that should be disabled, for +//! example, a 0 would target TIMER0. The \e ui32TimerSegment parameter allows +//! the caller to individually select a segment within a timer to be disabled, +//! such as TIMER0A, TIMER0B, or both. +//! +//! This function will stop a counter/timer from counting, but does not return +//! the count value to 'zero'. If you would like to reset the counter back to +//! zero, try the am_hal_ctimer_clear() function instead. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_stop(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t *pui32ConfigReg; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Clear the "enable" bit + // + AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0EN_M | + AM_REG_CTIMER_CTRL0_TMRB0EN_M)); + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_stop() + +//***************************************************************************** +// +//! @brief Stops a timer and resets its value back to zero. +//! +//! @param ui32TimerNumber is the number of the timer to clear. +//! +//! @param ui32TimerSegment specifies which segment of the timer should be +//! cleared. +//! +//! This function will stop a free-running counter-timer, reset its value to +//! zero, and leave the timer disabled. When you would like to restart the +//! counter, you will need to call am_hal_ctimer_start(). +//! +//! The \e ui32TimerSegment parameter allows the caller to individually select +//! a segment within, such as TIMER0A, TIMER0B, or both. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_clear(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t *pui32ConfigReg; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Set the "clear" bit + // + AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0CLR_M | + AM_REG_CTIMER_CTRL0_TMRB0CLR_M)); + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_clear() + +//***************************************************************************** +// +//! @brief Returns the current free-running value of the selected timer. +//! +//! @param ui32TimerNumber is the number of the timer to read. +//! @param ui32TimerSegment specifies which segment of the timer should be +//! read. +//! +//! This function returns the current free-running value of the selected timer. +//! +//! @note When reading from a linked timer, be sure to use AM_HAL_CTIMER both +//! for the segment argument. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return Current timer value. +// +//***************************************************************************** +uint32_t +am_hal_ctimer_read(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t ui32Value = 0; + uint32_t ui32Values[3] = {0}; + uint32_t ui32TimerAddrTbl[4] = + { + REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR0_O, + REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR1_O, + REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR2_O, + REG_CTIMER_BASEADDR + AM_REG_CTIMER_TMR3_O + }; + + // + // Read the timer with back2back reads. This is a workaround for a clock + // domain synchronization issue. Some timer bits may be slow to increment, + // which means that the value in the timer register will sometimes be + // wrong. + // + // The architecture guarantees that: + // + // 1) If the timer is running at a speed close to the core frequency, the + // core and timer clock domains will be synchronized, and no "bad" reads + // will happen. + // + // 2) Bad reads will only happen if the core reads the timer register while + // the timer value is transitioning from one count to the next. + // + // 3) The timer will resolve to the correct value within one 24 MHz clock + // cycle. + // + // If we read the timer three times in a row with back-to-back load + // instructions, then we can guarantee that the timer will only have time + // to increment once, and that only one of the three reads can be wrong. + // This routine will perform the back-to-back reads and return all three + // values. The rest of this fuction determines which value we should + // actually use. + // + back2back_reads(ui32TimerAddrTbl[ui32TimerNumber], ui32Values); + + // + // Shift or mask the values based on the given timer segment. + // + if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB ) + { + ui32Values[0] >>= 16; + ui32Values[1] >>= 16; + ui32Values[2] >>= 16; + } + else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA ) + { + ui32Values[0] &= 0xFFFF; + ui32Values[1] &= 0xFFFF; + ui32Values[2] &= 0xFFFF; + } + + // + // Now, we'll figure out which of the three values is the correct time. + // + if (ui32Values[0] == ui32Values[1]) + { + // + // If the first two values match, then neither one was a bad read. + // We'll take this as the current time. + // + ui32Value = ui32Values[1]; + } + else + { + // + // If the first two values didn't match, then one of them might be bad. + // If one of the first two values is bad, then the third one should + // always be correct. We'll take the third value as the correct time. + // + ui32Value = ui32Values[2]; + + // + // If all of the statements about the architecture are true, the third + // value should be correct, and it should always be within one count of + // either the first or the second value. + // + // Just in case, we'll check against the previous two values to make + // sure that our final answer was reasonable. If it isn't, we will + // flag it as a "bad read", and fail this assert statement. + // + // This shouldn't ever happen, and it hasn't ever happened in any of + // our tests so far. + // + am_hal_debug_assert_msg((adjacent(ui32Values[1], ui32Values[2]) || + adjacent(ui32Values[0], ui32Values[2])), + "Bad CTIMER read"); + } + + return ui32Value; +} // am_hal_ctimer_read() + +//***************************************************************************** +// +//! @brief Enable output to the timer pin +//! +//! @param ui32TimerNumber is the number of the timer to configure. +//! +//! @param ui32TimerSegment specifies which segment of the timer to use. +//! +//! This function will enable the output pin for the selected timer. The \e +//! ui32TimerSegment parameter allows the caller to individually select a +//! segment within, such as TIMER0A, TIMER0B, or both. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t *pui32ConfigReg; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Set the pin enable bit + // + AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0PE_M | + AM_REG_CTIMER_CTRL0_TMRB0PE_M)); + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_pin_enable() + +//***************************************************************************** +// +//! @brief Disable the output pin. +//! +//! @param ui32TimerNumber is the number of the timer to configure. +//! +//! @param ui32TimerSegment specifies which segment of the timer to use. +//! +//! This function will disable the output pin for the selected timer. The \e +//! ui32TimerSegment parameter allows the caller to individually select a +//! segment within, such as TIMER0A, TIMER0B, or both. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment) +{ + volatile uint32_t *pui32ConfigReg; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Clear the pin enable bit + // + AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0PE_M | + AM_REG_CTIMER_CTRL0_TMRB0PE_M)); + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_pin_disable() + +//***************************************************************************** +// +//! @brief Set the polarity of the output pin. +//! +//! @param ui32TimerNumber is the number of the timer to configure. +//! +//! @param ui32TimerSegment specifies which segment of the timer to use. +//! +//! @param bInvertOutpt determines whether the output should be inverted. If +//! true, the timer output pin for the selected timer segment will be +//! inverted. +//! +//! This function will set the polarity of the the output pin for the selected +//! timer. The \e ui32TimerSegment parameter allows the caller to individually +//! select a segment within, such as TIMER0A, TIMER0B, or both. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment, + bool bInvertOutput) +{ + volatile uint32_t *pui32ConfigReg; + + // + // Find the correct control register. + // + pui32ConfigReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Figure out if we're supposed to be setting or clearing the polarity bit. + // + if ( bInvertOutput ) + { + // + // Set the polarity bit to invert the output. + // + AM_REGVAL(pui32ConfigReg) |= (ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0POL_M | + AM_REG_CTIMER_CTRL0_TMRB0POL_M)); + } + else + { + // + // Clear the polarity bit. + // + AM_REGVAL(pui32ConfigReg) &= ~(ui32TimerSegment & + (AM_REG_CTIMER_CTRL0_TMRA0POL_M | + AM_REG_CTIMER_CTRL0_TMRB0POL_M)); + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_pin_invert() + +//***************************************************************************** +// +//! @brief Set a compare register. +//! +//! @param ui32TimerNumber is the number of the timer to configure. +//! +//! @param ui32TimerSegment specifies which segment of the timer to use. +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @param ui32CompareReg specifies which compare register should be set +//! (either 0 or 1) +//! +//! @param ui32Value is the value that should be written to the compare +//! register. +//! +//! This function allows the caller to set the values in the compare registers +//! for a timer. These registers control the period and duty cycle of the +//! timers and their associated output pins. Please see the datasheet for +//! further information on the operation of the compare registers. The \e +//! ui32TimerSegment parameter allows the caller to individually select a +//! segment within, such as TIMER0A, TIMER0B, or both. +//! +//! @note For simple manipulations of period or duty cycle for timers and PWMs, +//! you may find it easier to use the am_hal_ctimer_period_set() function. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_compare_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment, + uint32_t ui32CompareReg, uint32_t ui32Value) +{ + volatile uint32_t *pui32CmprRegA, *pui32CmprRegB; + uint32_t ui32CmprRegA, ui32CmprRegB; + + // + // Find the correct compare register to write. + // Assume A or BOTH. We'll change later if B. + // + pui32CmprRegA = (uint32_t *)(AM_REG_CTIMERn(0) + + AM_REG_CTIMER_CMPRA0_O + + (ui32TimerNumber * TIMER_OFFSET)); + pui32CmprRegB = pui32CmprRegA + CTIMER_CMPR_OFFSET; + + // + // Write the compare register with the selected value. + // Begin critical section while CMPR registers are modified. + // + AM_CRITICAL_BEGIN_ASM + + ui32CmprRegA = *pui32CmprRegA; + ui32CmprRegB = *pui32CmprRegB; + + if ( ui32CompareReg == 1 ) + { + // + // CMPR reg 1 + // Get the lower 16b (but may not be used if TIMERB). + // + ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value & 0xFFFF) ); + + // + // Get the upper 16b (but may not be used if TIMERA) + // + ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR0A0_M) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Value >> 16) ); + } + else + { + // + // CMPR reg 0 + // Get the lower 16b (but may not be used if TIMERB) + // + ui32CmprRegA = ( (ui32CmprRegA & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) | + AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value & 0xFFFF) ); + + // + // Set the upper 16b (but may not be used if TIMERA) + // + ui32CmprRegB = ( (ui32CmprRegB & AM_REG_CTIMER_CMPRA0_CMPR1A0_M) | + AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Value >> 16) ); + } + + if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB ) + { + *pui32CmprRegB = ui32CmprRegB; + } + else + { + // + // It's TIMERA or BOTH. + // + *pui32CmprRegA = ui32CmprRegA; + + if ( ui32TimerSegment == AM_HAL_CTIMER_BOTH ) + { + *pui32CmprRegB = ui32CmprRegB; + } + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_compare_set() + +//***************************************************************************** +// +//! @brief Set the period and duty cycle of a timer. +//! +//! @param ui32TimerNumber is the number of the timer to configure. +//! +//! @param ui32TimerSegment specifies which segment of the timer to use. +//! +//! @param ui32Period specifies the desired period. This parameter effectively +//! specifies the CTIMER CMPR field(s). The CMPR fields are handled in hardware +//! as (n+1) values, therefore ui32Period is actually specified as 1 less than +//! the desired period. Finally, as mentioned in the data sheet, the CMPR fields +//! cannot be 0 (a value of 1), so neither can ui32Period be 0. +//! +//! @param ui32OnTime set the number of clocks where the output signal is high. +//! +//! This function should be used for simple manipulations of the period and +//! duty cycle of a counter/timer. To set the period and/or duty cycle of a +//! linked timer pair, use AM_HAL_CTIMER_BOTH as the timer segment argument. If +//! you would like to set the period and/or duty cycle for both TIMERA and +//! TIMERB you will need to call this function twice: once for TIMERA, and once +//! for TIMERB. +//! +//! Valid values for ui32TimerSegment are: +//! +//! AM_HAL_CTIMER_TIMERA +//! AM_HAL_CTIMER_TIMERB +//! AM_HAL_CTIMER_BOTH +//! +//! @note The ui32OnTime parameter will only work if the timer is currently +//! operating in one of the PWM modes. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_period_set(uint32_t ui32TimerNumber, uint32_t ui32TimerSegment, + uint32_t ui32Period, uint32_t ui32OnTime) +{ + volatile uint32_t *pui32ControlReg; + volatile uint32_t *pui32CompareRegA; + volatile uint32_t *pui32CompareRegB; + uint32_t ui32Mode, ui32Comp0, ui32Comp1; + + // + // Find the correct control register to pull the function select field + // from. + // + pui32ControlReg = (uint32_t *)(AM_REG_CTIMERn(0) + AM_REG_CTIMER_CTRL0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Find the correct compare registers to write. + // + pui32CompareRegA = (uint32_t *)(AM_REG_CTIMERn(0) + + AM_REG_CTIMER_CMPRA0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + pui32CompareRegB = (uint32_t *)(AM_REG_CTIMERn(0) + + AM_REG_CTIMER_CMPRB0_O + + (ui32TimerNumber * TIMER_OFFSET)); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Extract the timer mode from the register based on the ui32TimerSegment + // selected by the user. + // + ui32Mode = *pui32ControlReg; + if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB ) + { + ui32Mode = ui32Mode >> 16; + } + + // + // Mask to get to the bits we're interested in. + // + ui32Mode = ui32Mode & AM_REG_CTIMER_CTRL0_TMRA0FN_M; + + // + // If the mode is a PWM mode, we'll need to calculate the correct CMPR0 and + // CMPR1 values here. + // + if (ui32Mode == AM_HAL_CTIMER_FN_PWM_ONCE || + ui32Mode == AM_HAL_CTIMER_FN_PWM_REPEAT) + { + ui32Comp0 = ui32Period - ui32OnTime; + ui32Comp1 = ui32Period; + } + else + { + ui32Comp0 = ui32Period; + ui32Comp1 = 0; + } + + // + // Based on the timer segment argument, write the calculated Compare 0 and + // Compare 1 values to the correct halves of the correct registers. + // + if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERA ) + { + // + // For timer A, write the values to the TIMERA compare register. + // + *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1)); + } + else if ( ui32TimerSegment == AM_HAL_CTIMER_TIMERB ) + { + // + // For timer B, write the values to the TIMERA compare register. + // + *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1)); + } + else + { + // + // For the linked case, write the lower halves of the values to the + // TIMERA compare register, and the upper halves to the TIMERB compare + // register. + // + *pui32CompareRegA = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1)); + + *pui32CompareRegB = (AM_REG_CTIMER_CMPRA0_CMPR0A0(ui32Comp0 >> 16) | + AM_REG_CTIMER_CMPRA0_CMPR1A0(ui32Comp1 >> 16)); + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_period_set() + +//***************************************************************************** +// +//! @brief Enable the TIMERA3 ADC trigger +//! +//! This function enables the ADC trigger within TIMERA3. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_adc_trigger_enable(void) +{ + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Enable the ADC trigger. + // + AM_REGn(CTIMER, 0, CTRL3) |= AM_REG_CTIMER_CTRL3_ADCEN_M; + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_adc_trigger_enable() + +//***************************************************************************** +// +//! @brief Disable the TIMERA3 ADC trigger +//! +//! This function disables the ADC trigger within TIMERA3. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_adc_trigger_disable(void) +{ + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Disable the ADC trigger. + // + AM_REGn(CTIMER, 0, CTRL3) &= ~AM_REG_CTIMER_CTRL3_ADCEN_M; + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_adc_trigger_disable() + +//***************************************************************************** +// +//! @brief Enables the selected timer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will enable the selected interrupts in the main CTIMER +//! interrupt enable register. In order to receive an interrupt from a timer, +//! you will need to enable the interrupt for that timer in this main register, +//! as well as in the timer control register (accessible though +//! am_hal_ctimer_config()), and in the NVIC. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_enable(uint32_t ui32Interrupt) +{ + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Enable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, INTEN) |= ui32Interrupt; + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_int_enable() + +//***************************************************************************** +// +//! @brief Return the enabled timer interrupts. +//! +//! This function will return all enabled interrupts in the main CTIMER +//! interrupt enable register. +//! +//! @return return enabled interrupts. This will be a logical or of: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return Return the enabled timer interrupts. +// +//***************************************************************************** +uint32_t +am_hal_ctimer_int_enable_get(void) +{ + // + // Return enabled interrupts. + // + return AM_REGn(CTIMER, 0, INTEN); +} // am_hal_ctimer_int_enable_get() + +//***************************************************************************** +// +//! @brief Disables the selected timer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will disable the selected interrupts in the main CTIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_disable(uint32_t ui32Interrupt) +{ + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Disable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, INTEN) &= ~ui32Interrupt; + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} // am_hal_ctimer_int_disable() + +//***************************************************************************** +// +//! @brief Clears the selected timer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will clear the selected interrupts in the main CTIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_clear(uint32_t ui32Interrupt) +{ + // + // Disable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, INTCLR) = ui32Interrupt; +} // am_hal_ctimer_int_clear() + +//***************************************************************************** +// +//! @brief Sets the selected timer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will set the selected interrupts in the main CTIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ctimer_int_set(uint32_t ui32Interrupt) +{ + // + // Set the interrupts. + // + AM_REGn(CTIMER, 0, INTSET) = ui32Interrupt; +} // am_hal_ctimer_int_set() + +//***************************************************************************** +// +//! @brief Returns either the enabled or raw timer interrupt status. +//! +//! This function will return the timer interrupt status. +//! +//! @return bEnabledOnly if true returns the status of the enabled interrupts +//! only. +//! +//! The return value will be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_CTIMER_INT_TIMERA0C0 +//! AM_HAL_CTIMER_INT_TIMERA0C1 +//! AM_HAL_CTIMER_INT_TIMERB0C0 +//! AM_HAL_CTIMER_INT_TIMERB0C1 +//! AM_HAL_CTIMER_INT_TIMERA1C0 +//! AM_HAL_CTIMER_INT_TIMERA1C1 +//! AM_HAL_CTIMER_INT_TIMERB1C0 +//! AM_HAL_CTIMER_INT_TIMERB1C1 +//! AM_HAL_CTIMER_INT_TIMERA2C0 +//! AM_HAL_CTIMER_INT_TIMERA2C1 +//! AM_HAL_CTIMER_INT_TIMERB2C0 +//! AM_HAL_CTIMER_INT_TIMERB2C1 +//! AM_HAL_CTIMER_INT_TIMERA3C0 +//! AM_HAL_CTIMER_INT_TIMERA3C1 +//! AM_HAL_CTIMER_INT_TIMERB3C0 +//! AM_HAL_CTIMER_INT_TIMERB3C1 +//! +//! @return Returns either the timer interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_ctimer_int_status_get(bool bEnabledOnly) +{ + // + // Return the desired status. + // + + if ( bEnabledOnly ) + { + uint32_t u32RetVal; + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + u32RetVal = AM_REGn(CTIMER, 0, INTSTAT); + u32RetVal &= AM_REGn(CTIMER, 0, INTEN); + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM + + return u32RetVal; + } + else + { + return AM_REGn(CTIMER, 0, INTSTAT); + } +} // am_hal_ctimer_int_status_get() + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.h b/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.h new file mode 100644 index 0000000000..fa1ebe16c4 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_ctimer.h @@ -0,0 +1,278 @@ +//***************************************************************************** +// +// am_hal_ctimer.h +//! @file +//! +//! @brief Functions for accessing and configuring the CTIMER. +//! +//! @addtogroup ctimer2 Counter/Timer (CTIMER) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_CTIMER_H +#define AM_HAL_CTIMER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! Number of timers +// +//***************************************************************************** +#define AM_HAL_CTIMER_TIMERS_NUM 4 + +//***************************************************************************** +// +//! Timer offset value +// +//***************************************************************************** +#define AM_HAL_CTIMER_TIMER_OFFSET (AM_REG_CTIMER_TMR1_O - AM_REG_CTIMER_TMR0_O) + +//***************************************************************************** +// +//! @name Interrupt Status Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to set and clear interrupt bits +//! @{ +// +//***************************************************************************** +#define AM_HAL_CTIMER_INT_TIMERA0C0 AM_REG_CTIMER_INTEN_CTMRA0C0INT_M +#define AM_HAL_CTIMER_INT_TIMERA0C1 AM_REG_CTIMER_INTEN_CTMRA0C1INT_M +#define AM_HAL_CTIMER_INT_TIMERA1C0 AM_REG_CTIMER_INTEN_CTMRA1C0INT_M +#define AM_HAL_CTIMER_INT_TIMERA1C1 AM_REG_CTIMER_INTEN_CTMRA1C1INT_M +#define AM_HAL_CTIMER_INT_TIMERA2C0 AM_REG_CTIMER_INTEN_CTMRA2C0INT_M +#define AM_HAL_CTIMER_INT_TIMERA2C1 AM_REG_CTIMER_INTEN_CTMRA2C1INT_M +#define AM_HAL_CTIMER_INT_TIMERA3C0 AM_REG_CTIMER_INTEN_CTMRA3C0INT_M +#define AM_HAL_CTIMER_INT_TIMERA3C1 AM_REG_CTIMER_INTEN_CTMRA3C1INT_M + +#define AM_HAL_CTIMER_INT_TIMERB0C0 AM_REG_CTIMER_INTEN_CTMRB0C0INT_M +#define AM_HAL_CTIMER_INT_TIMERB0C1 AM_REG_CTIMER_INTEN_CTMRB0C1INT_M +#define AM_HAL_CTIMER_INT_TIMERB1C0 AM_REG_CTIMER_INTEN_CTMRB1C0INT_M +#define AM_HAL_CTIMER_INT_TIMERB1C1 AM_REG_CTIMER_INTEN_CTMRB1C1INT_M +#define AM_HAL_CTIMER_INT_TIMERB2C0 AM_REG_CTIMER_INTEN_CTMRB2C0INT_M +#define AM_HAL_CTIMER_INT_TIMERB2C1 AM_REG_CTIMER_INTEN_CTMRB2C1INT_M +#define AM_HAL_CTIMER_INT_TIMERB3C0 AM_REG_CTIMER_INTEN_CTMRB3C0INT_M +#define AM_HAL_CTIMER_INT_TIMERB3C1 AM_REG_CTIMER_INTEN_CTMRB3C1INT_M + +// +// Deprecated, use the newer macros above. +// +#define AM_HAL_CTIMER_INT_TIMERA0 AM_HAL_CTIMER_INT_TIMERA0C0 +#define AM_HAL_CTIMER_INT_TIMERB0 AM_HAL_CTIMER_INT_TIMERB0C0 +#define AM_HAL_CTIMER_INT_TIMERA1 AM_HAL_CTIMER_INT_TIMERA1C0 +#define AM_HAL_CTIMER_INT_TIMERB1 AM_HAL_CTIMER_INT_TIMERB1C0 +#define AM_HAL_CTIMER_INT_TIMERA2 AM_HAL_CTIMER_INT_TIMERA2C0 +#define AM_HAL_CTIMER_INT_TIMERB2 AM_HAL_CTIMER_INT_TIMERB2C0 +#define AM_HAL_CTIMER_INT_TIMERA3 AM_HAL_CTIMER_INT_TIMERA3C0 +#define AM_HAL_CTIMER_INT_TIMERB3 AM_HAL_CTIMER_INT_TIMERB3C0 +//! @} + +//***************************************************************************** +// +//! @name Configuration options +//! @brief Configuration options for \e am_hal_ctimer_config_t +//! +//! These options are to be used with the \e am_hal_ctimer_config_t structure +//! used by \e am_hal_ctimer_config +//! @{ +// +//***************************************************************************** +#define AM_HAL_CTIMER_CLK_PIN AM_REG_CTIMER_CTRL0_TMRA0CLK(0x0) +#define AM_HAL_CTIMER_HFRC_12MHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x1) +#define AM_HAL_CTIMER_HFRC_3MHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x2) +#define AM_HAL_CTIMER_HFRC_187_5KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x3) +#define AM_HAL_CTIMER_HFRC_47KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x4) +#define AM_HAL_CTIMER_HFRC_12KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x5) +#define AM_HAL_CTIMER_XT_32_768KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x6) +#define AM_HAL_CTIMER_XT_16_384KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x7) +#define AM_HAL_CTIMER_XT_2_048KHZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x8) +#define AM_HAL_CTIMER_XT_256HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0x9) +#define AM_HAL_CTIMER_LFRC_512HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0xA) +#define AM_HAL_CTIMER_LFRC_32HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0xB) +#define AM_HAL_CTIMER_LFRC_1HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0xC) +#define AM_HAL_CTIMER_LFRC_1_16HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0xD) +#define AM_HAL_CTIMER_RTC_100HZ AM_REG_CTIMER_CTRL0_TMRA0CLK(0xE) +#define AM_HAL_CTIMER_HCLK AM_REG_CTIMER_CTRL0_TMRA0CLK(0xF) +#define AM_HAL_CTIMER_BUCK AM_REG_CTIMER_CTRL0_TMRA0CLK(0x10) +//! @} + +//***************************************************************************** +// +// Timer function macros. +// +//***************************************************************************** +#define AM_HAL_CTIMER_FN_ONCE AM_REG_CTIMER_CTRL0_TMRA0FN(0) +#define AM_HAL_CTIMER_FN_REPEAT AM_REG_CTIMER_CTRL0_TMRA0FN(1) +#define AM_HAL_CTIMER_FN_PWM_ONCE AM_REG_CTIMER_CTRL0_TMRA0FN(2) +#define AM_HAL_CTIMER_FN_PWM_REPEAT AM_REG_CTIMER_CTRL0_TMRA0FN(3) +#define AM_HAL_CTIMER_FN_CONTINUOUS AM_REG_CTIMER_CTRL0_TMRA0FN(4) + +//***************************************************************************** +// +// Half-timer options. +// +//***************************************************************************** +#define AM_HAL_CTIMER_INT_ENABLE AM_REG_CTIMER_CTRL0_TMRA0IE0_M +#define AM_HAL_CTIMER_PIN_ENABLE AM_REG_CTIMER_CTRL0_TMRA0PE_M +#define AM_HAL_CTIMER_PIN_INVERT AM_REG_CTIMER_CTRL0_TMRA0POL_M +#define AM_HAL_CTIMER_CLEAR AM_REG_CTIMER_CTRL0_TMRA0CLR_M + +//***************************************************************************** +// +// Additional timer options. +// +//***************************************************************************** +#define AM_HAL_CTIMER_LINK AM_REG_CTIMER_CTRL0_CTLINK0_M +#define AM_HAL_CTIMER_ADC_TRIG AM_REG_CTIMER_CTRL3_ADCEN_M + +//***************************************************************************** +// +// Timer selection macros. +// +//***************************************************************************** +#define AM_HAL_CTIMER_TIMERA 0x0000FFFF +#define AM_HAL_CTIMER_TIMERB 0xFFFF0000 +#define AM_HAL_CTIMER_BOTH 0xFFFFFFFF +//! @} + +//***************************************************************************** +// +// Timer configuration structure +// +//***************************************************************************** +typedef struct +{ + // + //! Set to 1 to operate this timer as a 32-bit timer instead of two 16-bit + //! timers. + // + uint32_t ui32Link; + + // + //! Configuration options for TIMERA + // + uint32_t ui32TimerAConfig; + + // + //! Configuration options for TIMERB + // + uint32_t ui32TimerBConfig; + +} +am_hal_ctimer_config_t; + +//***************************************************************************** +// +// Function pointer type for CTimer interrupt handlers. +// +//***************************************************************************** +typedef void (*am_hal_ctimer_handler_t)(void); + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_ctimer_config(uint32_t ui32TimerNumber, + am_hal_ctimer_config_t *psConfig); + +extern void am_hal_ctimer_config_single(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment, + uint32_t ui32ConfigVal); + +extern void am_hal_ctimer_start(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern void am_hal_ctimer_stop(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern void am_hal_ctimer_clear(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern uint32_t am_hal_ctimer_read(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern void am_hal_ctimer_pin_enable(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern void am_hal_ctimer_pin_disable(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment); + +extern void am_hal_ctimer_pin_invert(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment, + bool bInvertOutput); + +extern void am_hal_ctimer_compare_set(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment, + uint32_t ui32CompareReg, + uint32_t ui32Value); + +extern void am_hal_ctimer_period_set(uint32_t ui32TimerNumber, + uint32_t ui32TimerSegment, + uint32_t ui32Period, + uint32_t ui32OnTime); + +extern void am_hal_ctimer_adc_trigger_enable(void); +extern void am_hal_ctimer_adc_trigger_disable(void); +extern void am_hal_ctimer_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_ctimer_int_enable_get(void); +extern void am_hal_ctimer_int_disable(uint32_t ui32Interrupt); +extern void am_hal_ctimer_int_set(uint32_t ui32Interrupt); +extern void am_hal_ctimer_int_clear(uint32_t ui32Interrupt); +extern uint32_t am_hal_ctimer_int_status_get(bool bEnabledOnly); +extern void am_hal_ctimer_int_register(uint32_t ui32Interrupt, + am_hal_ctimer_handler_t pfnHandler); +extern void am_hal_ctimer_int_service(uint32_t ui32Status); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_CTIMER_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_debug.c b/bsp/apollo2/libraries/drivers/hal/am_hal_debug.c new file mode 100644 index 0000000000..4078b5a5a0 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_debug.c @@ -0,0 +1,81 @@ +//***************************************************************************** +// +// am_hal_debug.c +//! @file +//! +//! @brief Useful functions for debugging. +//! +//! These functions and macros were created to assist with debugging. They are +//! intended to be as unintrusive as possible and designed to be removed from +//! the compilation of a project when they are no longer needed. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Default implementation of a failed ASSERT statement. +//! +//! @param pcFile is the name of the source file where the error occurred. +//! @param ui32Line is the line number where the error occurred. +//! @param pcMessage is an optional message describing the failure. +//! +//! This function is called by am_hal_debug_assert() macro when the supplied +//! condition is not true. The implementation here simply halts the application +//! for further analysis. Individual applications may define their own +//! implementations of am_hal_debug_error() to provide more detailed feedback +//! about the failed am_hal_debug_assert() statement. +//! +//! @return +// +//***************************************************************************** +#if defined (__IAR_SYSTEMS_ICC__) +__weak void +#else +void __attribute__((weak)) +#endif +am_hal_debug_error(const char *pcFile, uint32_t ui32Line, const char *pcMessage) +{ + // + // Halt for analysis. + // + while(1); +} diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_debug.h b/bsp/apollo2/libraries/drivers/hal/am_hal_debug.h new file mode 100644 index 0000000000..a482799c4f --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_debug.h @@ -0,0 +1,89 @@ +//***************************************************************************** +// +// am_hal_debug.h +//! @file +//! +//! @brief Useful macros for debugging. +//! +//! These functions and macros were created to assist with debugging. They are +//! intended to be as unintrusive as possible and designed to be removed from +//! the compilation of a project when they are no longer needed. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_DEBUG_H +#define AM_HAL_DEBUG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Debug assert macros. +// +//***************************************************************************** +#ifndef AM_HAL_DEBUG_NO_ASSERT + +#define am_hal_debug_assert_msg(bCondition, pcMessage) \ + if ( !(bCondition)) am_hal_debug_error(__FILE__, __LINE__, pcMessage) + +#define am_hal_debug_assert(bCondition) \ + if ( !(bCondition)) am_hal_debug_error(__FILE__, __LINE__, 0) + +#else + +#define am_hal_debug_assert_msg(bCondition, pcMessage) +#define am_hal_debug_assert(bCondition) + +#endif // AM_DEBUG_ASSERT + +//***************************************************************************** +// +// External function prototypes. +// +//***************************************************************************** +extern void am_hal_debug_error(const char *pcFile, uint32_t ui32Line, + const char *pcMessage); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_DEBUG_H + diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_flash.c b/bsp/apollo2/libraries/drivers/hal/am_hal_flash.c new file mode 100644 index 0000000000..cd38da812c --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_flash.c @@ -0,0 +1,1449 @@ +//***************************************************************************** +// +// am_hal_flash.c +//! @file +//! +//! @brief Functions for performing Flash operations. +//! +//! @addtogroup flash2 Flash +//! @ingroup apollo2hal +//! +//! IMPORTANT: Interrupts are active during execution of all HAL flash +//! functions. If an interrupt occurs during execution of a flash function +//! that programs or erases flash or INFO space, errors will occur if the +//! interrupt service routine (ISR) is located in on-chip flash. +//! If interrupts are expected during execution of a flash function that +//! programs or erases either flash or INFO space: +//! - Interrupts must be disabled via a critical section handler prior to +//! calling the flash function. +//! - Alternatively, applicable ISRs must be located in non-flash address space +//! (i.e. SRAM, off-chip ROM, etc.). +//! +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +// +// Look-up table +// +g_am_hal_flash_t g_am_hal_flash = +{ + // + // The basics. + // + // flash_mass_erase() + ((int (*) (uint32_t, uint32_t)) 0x0800004d), + // flash_page_erase() + ((int (*) (uint32_t, uint32_t, uint32_t)) 0x08000051), + // flash_program_main() + ((int (*) (uint32_t, uint32_t *, uint32_t *, uint32_t)) 0x08000055), + // flash_program_info() + ((int (*) (uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t)) 0x08000059), + + // + // Non-blocking variants, but be careful these are not interrupt safe so + // mask interrupts while these very long operations proceed. + // + // flash_mass_erase_nb() + ((int (*)(uint32_t, uint32_t)) 0x0800006d), + // flash_page_erase_nb() + ((int (*)(uint32_t, uint32_t, uint32_t)) 0x08000071), + // flash_nb_operation_complete() + ((bool (*)(void)) 0x0800007d), + + // + // Essentially these are recovery options. + // + // flash_erase_info() + ((int (*)(uint32_t, uint32_t)) 0x08000081), + // flash_erase_main_plus_info() + ((int (*)(uint32_t, uint32_t)) 0x08000089), + // flash_erase_main_plus_info_both_instances() + ((int (*)(uint32_t)) 0x08000091), + // flash_recovery() + ((void (*)(uint32_t)) 0x08000099), + + // + // Useful utilities. + // + // flash_util_read_word() + ((uint32_t (*)(uint32_t*)) 0x08000075), + // flash_util_write_word() + ((void (*)(uint32_t*, uint32_t)) 0x08000079), + // delay_cycles() + ((void (*)(uint32_t)) 0x0800009d), + + // + // The following functions pointers must never be called from user + // programs. They are here primarily to document these entry points + // which are usable from a debugger or debugger script. + // + // flash_program_main_sram() + ((void (*) (void)) 0x0800005d), + // flash_program_info_sram() + ((void (*) (void)) 0x08000061), + // flash_erase_main_pages_sram() + ((void (*) (void)) 0x08000065), + // flash_mass_erase_sram() + ((void (*) (void)) 0x08000069), + // flash_erase_info_sram() + ((void (*)(void)) 0x08000085), + // flash_erase_main_plus_info_sram() + ((void (*)(void)) 0x0800008d) +}; + +//***************************************************************************** +// +//! @brief This function performs a mass erase on a flash instance. +//! +//! @param ui32Value - The flash program key. +//! @param ui32FlashInst - The flash instance to erase. +//! +//! This function will erase the desired instance of flash. +//! +//! @note For Apollo2, each flash instance contains a maximum of 512KB. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_mass_erase(uint32_t ui32Value, uint32_t ui32FlashInst) +{ + return g_am_hal_flash.flash_mass_erase(ui32Value, ui32FlashInst); +} + +//***************************************************************************** +// +//! @brief This function performs a page erase on a flash instance. +//! +//! @param ui32Value - The flash program key. +//! @param ui32FlashInst - The flash instance to reference the page number with. +//! @param ui32PageNum - The flash page relative to the specified instance. +//! +//! This function will erase the desired flash page in the desired instance of +//! flash. +//! +//! @note For Apollo2, each flash page is 8KB (or AM_HAL_FLASH_PAGE_SIZE). +//! Each flash instance contains a maximum of 64 pages (or +//! AM_HAL_FLASH_INSTANCE_PAGES). +//! +//! @note When given an absolute flash address, a couple of helpful macros can +//! be utilized when calling this function. +//! For example: +//! am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, +//! AM_HAL_FLASH_ADDR2INST(ui32Addr), +//! AM_HAL_FLASH_ADDR2PAGE(ui32Addr) ); +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_page_erase(uint32_t ui32Value, uint32_t ui32FlashInst, + uint32_t ui32PageNum) +{ + return g_am_hal_flash.flash_page_erase(ui32Value, + ui32FlashInst, + ui32PageNum); +} + +//***************************************************************************** +// +//! @brief This programs up to N words of the Main array on one flash instance. +//! +//! @param ui32Value - The programming key, AM_HAL_FLASH_PROGRAM_KEY. +//! @param pui32Src - Pointer to word aligned array of data to program into +//! the flash instance. +//! @param pui32Dst - Pointer to the word aligned flash location where +//! programming of the flash instance is to begin. +//! @param ui32NumWords - The number of words to be programmed. +//! +//! This function will program multiple words in main flash. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_program_main(uint32_t ui32Value, uint32_t *pui32Src, + uint32_t *pui32Dst, uint32_t ui32NumWords) +{ + return g_am_hal_flash.flash_program_main(ui32Value, pui32Src, + pui32Dst, ui32NumWords); +} + +//***************************************************************************** +// +//! @brief This function programs multiple words in the customer INFO space. +//! +//! @param ui32Value - The customer INFO space key. +//! @param ui32InfoInst - The INFO space instance, 0 or 1. +//! @param *pui32Src - Pointer to word aligned array of data to program into +//! the customer INFO space. +//! @param ui32Offset - Word offset into customer INFO space (offset of 0 is +//! the first word, 1 is second word, etc.). +//! @param ui32NumWords - The number of words to be programmed, must not +//! exceed AM_HAL_FLASH_INFO_SIZE/4. +//! +//! This function will program multiple words in the customer INFO space. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_program_info(uint32_t ui32Value, uint32_t ui32InfoInst, + uint32_t *pui32Src, uint32_t ui32Offset, + uint32_t ui32NumWords) +{ + return g_am_hal_flash.flash_program_info(ui32Value, 0, pui32Src, + ui32Offset, ui32NumWords); +} + +//***************************************************************************** +// +//! @brief This function erases an instance of the customer INFO space. +//! +//! @param ui32ProgramKey - The customer INFO space programming key +//! (AM_HAL_FLASH_PROGRAM_KEY). +//! @param ui32Inst - The flash instance, either 0 or 1. +//! +//! This function will erase the the customer INFO space of the specified +//! instance. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_erase_info(uint32_t ui32ProgramKey, + uint32_t ui32Inst) +{ + return g_am_hal_flash.flash_erase_info(ui32ProgramKey, ui32Inst); +} + +//***************************************************************************** +// +//! @brief This function erases the main instance + the customer INFO space. +//! +//! @param ui32ProgramKey - The customer INFO space key. +//! @param ui32Inst - The flash instance, either 0 or 1. +//! +//! This function will erase the main flash + the customer INFO space of the +//! specified instance. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_erase_main_plus_info(uint32_t ui32ProgramKey, + uint32_t ui32Inst) +{ + return g_am_hal_flash.flash_erase_main_plus_info(ui32ProgramKey, + ui32Inst); +} + +//***************************************************************************** +// +//! @brief This function erases the main flash + the customer INFO space. +//! +//! @param ui32ProgramKey - The customer INFO space key. +//! +//! This function will erase both instances the main flash + the +//! customer INFO space. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return 0 for success, non-zero for failure. +// +//***************************************************************************** +int +am_hal_flash_erase_main_plus_info_both_instances(uint32_t ui32ProgramKey) +{ + return g_am_hal_flash.flash_erase_main_plus_info_both_instances( + ui32ProgramKey); +} + +//***************************************************************************** +// +//! @brief This function erases both main flash instances + both customer INFO +//! space instances. +//! +//! @param ui32RecoveryKey - The recovery key. +//! +//! This function erases both main instances and both customer INFOinstances +//! even if the customer INFO space is programmed to not be erasable. This +//! function completely erases the flash main and info instances and wipes the +//! SRAM. Upon completion of the erasure operations, it does a POI (power on +//! initialization) reset. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Never Returns!!! +// +//***************************************************************************** +void +am_hal_flash_recovery(uint32_t ui32RecoveryKey) +{ + g_am_hal_flash.flash_recovery(ui32RecoveryKey); +} + +//***************************************************************************** +// +//! @brief Return ui32 value obtained from anywhere in D Code or System Bus +//! +//! @param ui32Address - return the value corresponding to this location. +//! +//! Use this function to read a value from various peripheral locations +//! that must be read from code running external to flash. +//! +//! @return the value found +// +//***************************************************************************** +uint32_t +am_hal_flash_load_ui32(uint32_t ui32Address) +{ + return g_am_hal_flash.flash_util_read_word((uint32_t*)ui32Address); +} + +//***************************************************************************** +// +//! @brief Use the bootrom to write to a location in SRAM or the system bus. +//! +//! @param ui32Address - Store the data value corresponding to this location. +//! @param ui32Data - 32-bit Data to be stored. +//! +//! Use this function to store a value to various peripheral or SRAM locations +//! that can not be touched from code running in SRAM or FLASH. There is no +//! known need for this function in Apollo2 at this time. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_flash_store_ui32(uint32_t ui32Address, uint32_t ui32Data) +{ + g_am_hal_flash.flash_util_write_word((uint32_t*)ui32Address, + ui32Data); +} + +//***************************************************************************** +// +//! @brief Use the bootrom to implement a spin loop. +//! +//! @param ui32Iterations - Number of iterations to delay. +//! +//! Use this function to implement a CPU busy waiting spin loop without cache +//! or delay uncertainties. +//! +//! Note that the ROM-based function executes at 3 cycles per iteration plus +//! the regular function call, entry, and exit overhead. +//! The call and return overhead, including the call to this function, is +//! somewhere in the neighborhood of 14 cycles, or 4.7 iterations. +//! +//! Example: +//! - MCU operating at 48MHz -> 20.83 ns / cycle +//! - Therefore each iteration (once inside the bootrom function) will consume +//! 62.5ns. +//! - The total overhead (assuming 14 cycles) is 292ns. +//! - For ui32Iterations=28: Total delay time = 0.292 + (0.0625 * 28) = 2.04us. +//! +//! The FLASH_CYCLES_US(n) macro can be used with am_hal_flash_delay() to +//! get an approximate microsecond delay. +//! e.g. For a 2us delay, use: +//! am_hal_flash_delay( FLASH_CYCLES_US(2) ); +//! +//! @note Interrupts are active during execution of this function. Therefore, +//! any interrupt taken will affect the delay timing. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_flash_delay(uint32_t ui32Iterations) +{ + g_am_hal_flash.delay_cycles(ui32Iterations); +} + +//***************************************************************************** +// +//! @brief Static Helper Function to check customer info valid bits erasure. +//! +//! Use this function to test the state of the 128 valid bits at the beginning +//! of customer info space. If these are all erased then return true. +//! +//! @return true if the customer info bits are currently erased. +// +//***************************************************************************** +static bool +customer_info_signature_erased(void) +{ + uint32_t *pui32Signature = (uint32_t *) AM_HAL_FLASH_INFO_ADDR; + + return ( (pui32Signature[3] == 0xFFFFFFFF) && + (pui32Signature[2] == 0xFFFFFFFF) && + (pui32Signature[1] == 0xFFFFFFFF) && + (pui32Signature[0] == 0xFFFFFFFF) ) ? true : false; +} + +//***************************************************************************** +// +//! @brief Static Helper Function to set customer info valid bits +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space. If these bits are not set correctly then the +//! customer protection bits in the INFO space will not be honored by the +//! hardware. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +static int +customer_info_signature_set(void) +{ + uint32_t ui32Valid[4]; + int iRC; + + // + // If they are already set then we are done. + // + if ( am_hal_flash_customer_info_signature_check() ) + { + return 0; + } + + // + // If they are not erased at this point we have an error. + // + if ( !customer_info_signature_erased() ) + { + return (2 << 16); + } + + // + // OK they need to be set so do it. + // + ui32Valid[3] = AM_HAL_FLASH_INFO_SIGNATURE3; + ui32Valid[2] = AM_HAL_FLASH_INFO_SIGNATURE2; + ui32Valid[1] = AM_HAL_FLASH_INFO_SIGNATURE1; + ui32Valid[0] = AM_HAL_FLASH_INFO_SIGNATURE0; + + iRC = g_am_hal_flash.flash_program_info(AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + ui32Valid, // source data + 0, // offset + 4); // number of words + return iRC | ((iRC) ? (1 << 16) : 0); +} + +//***************************************************************************** +// +//! @brief Check that the customer info bits are valid. +//! +//! Use this function to test the state of the 128 valid bits at the beginning +//! of customer info space. If these are not set correctly then the customer +//! protection bits in the INFO space will not be honored by the hardware. +//! +//! @return true if valid. +// +//***************************************************************************** +bool +am_hal_flash_customer_info_signature_check(void) +{ + uint32_t *pui32Signature = (uint32_t *)AM_HAL_FLASH_INFO_ADDR; + + return ( (pui32Signature[3] == AM_HAL_FLASH_INFO_SIGNATURE3) && + (pui32Signature[2] == AM_HAL_FLASH_INFO_SIGNATURE2) && + (pui32Signature[1] == AM_HAL_FLASH_INFO_SIGNATURE1) && + (pui32Signature[0] == AM_HAL_FLASH_INFO_SIGNATURE0) ); +} + +//***************************************************************************** +// +//! @brief INFO signature set. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +bool +am_hal_flash_info_signature_set(void) +{ + // + // Check and set signature. + // + return customer_info_signature_set() ? false : true; +} + +//***************************************************************************** +// +//! @brief Disable FLASH INFO space. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Then disable FLASH erasure. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_info_erase_disable(void) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Clear bit in INFO space to disable erasure. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + ~AM_HAL_FLASH_INFO_SECURITY_ENINFOERASE_M; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief Check for Disabled FLASH INFO space. +//! +//! Use this function to determine whether FLASH INFO erasure is disabled. +//! +//! @return true if FLASH INFO erase is disabled, otherwise false. +// +//***************************************************************************** +bool +am_hal_flash_info_erase_disable_check(void) +{ + // + // If they are erased at this point then SRAM wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return false; + } + + // + // If they are not valid at this point then SRAM wipe can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return false; + } + + // + // Looking good so far, now check the SRAM WIPE bit. + // + return AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_ENINFOERASE_M ? false : true; +} + +//***************************************************************************** +// +//! @brief Mask off 1 to 4 quadrants of FLASH INFO space for programming. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Then and the mask bits with the INFO +//! space programming disable bits. +//! +//! @param ui32Mask - A mask of the 4 quadrants of info space where +//! bit0 = First quadrant (first 2KB). +//! bit1 = Second quadrant (second 2KB). +//! bit2 = Third quadrant (third 2KB). +//! bit3 = Fourth quadrant (fourth 2KB). +//! +//! @note This function disables only, any quadrant already disabled is not +//! reenabled. That is, any ui32Mask bits specified as 0 are essentially nops. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_info_program_disable(uint32_t ui32Mask) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Make sure we have a valid mask and get the mask into the correct position. + // + ui32Mask <<= AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_S; + ui32Mask &= AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_M; + + // + // The security bit set to 1 enables programming, 0 disables programming. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & ~ui32Mask; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief Return a mask specifying which quadrants of customer INFO space have +//! been disabled for programming. +//! +//! Use this function to determine whether programming of customer INFO space +//! has been disabled. +//! +//! @return A 4-bit mask of the disabled quadrants. +//! 0xFFFFFFFF indicates an error. +//! 0x0 indicates all customer INFO space programming is enabled. +//! 0xF indicates all customer INFO space programming is disabled. +//! bit0 indicates the first customer INFO space is disabled for programming. +//! bit1 indicates the second customer INFO space is disabled for programming. +//! bit2 indicates the third customer INFO space is disabled for programming. +//! bit3 indicates the fourth customer INFO space is disabled for programming. +// +//***************************************************************************** +uint32_t +am_hal_flash_info_program_disable_get(void) +{ + // + // If they are erased at this point then SRAM wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return 0xFFFFFFFF; + } + + // + // If not valid at this point, then INFO programming can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return 0xFFFFFFFF; + } + + // + // Looking good so far, now return a mask of the disabled bits. + // + return ((AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_M) ^ + AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_M) >> + AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_S; +} + +//***************************************************************************** +// +//! @brief Enable FLASH debugger protection (FLASH gets wiped if a debugger is +//! connected). +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Then set the FLASH wipe bit to zero. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_wipe_flash_enable(void) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Clear the FLASH Wipe bit. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + ~AM_HAL_FLASH_INFO_SECURITY_FLASHWIPE_M; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief check for FLASH wipe protection enabled. +//! +//! Use this function to determine if FLASH wipe protection is enabled. +//! +//! @return true if FLASH wipe protection is enabled, otherwise false. +// +//***************************************************************************** +bool +am_hal_flash_wipe_flash_enable_check(void) +{ + // + // If they are erased at this point then flash wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return false; + } + + // + // If they are not valid at this point then flash wipe can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return false; + } + + // + // Looking good so far, now check the Flash WIPE bit. + // + return AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_FLASHWIPE_M ? false : true; +} + +//***************************************************************************** +// +//! @brief Enable SRAM protection so SRAM gets wiped if a debgger is connected. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Then set the SRAM wipe bit to zero. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_wipe_sram_enable(void) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Clear the SRAM Wipe bit. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + ~AM_HAL_FLASH_INFO_SECURITY_SRAMWIPE_M; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief check for SRAM protection enabled. +//! +//! Use this function to determine if SRAM protection is enabled. +//! +//! @return true if SRAM wipe protection is enabled, otherwise false. +// +//***************************************************************************** +bool +am_hal_flash_wipe_sram_enable_check(void) +{ + // + // If they are erased at this point then SRAM wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return false; + } + + // + // If they are not vale at this point then SRAM wipe can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return false; + } + + // + // Looking good so far, now check the SRAM WIPE bit. + // + return AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_SRAMWIPE_M ? false : true; +} + +//***************************************************************************** +// +//! @brief Disable Output from ITM/SWO. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Set the SWO disable bit to zero. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_swo_disable(void) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Clear the SWO bit. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + ~AM_HAL_FLASH_INFO_SECURITY_SWOCTRL_M; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief check for SWO disabled. +//! +//! Use this function to determine if the SWO is disabled. +//! +//! @return true if the ITM/SWO is disabled, otherwise false. +// +//***************************************************************************** +bool +am_hal_flash_swo_disable_check(void) +{ + // + // If they are erased at this point then SRAM wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return false; + } + + // + // If they are not vale at this point then SRAM wipe can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return false; + } + + // + // Looking good so far, now check the SWO bit. + // + return AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_SWOCTRL_M ? false : true; +} + +//***************************************************************************** +// +//! @brief Disable Connections from a debugger on the SWD interface. +//! +//! Use this function to set the state of the 128 valid bits at the beginning +//! of customer info space, if needed. Set the debugger disable bit to zero. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return Zero for success. Non-Zero for errors. +// +//***************************************************************************** +int32_t +am_hal_flash_debugger_disable(void) +{ + int iRC; + uint32_t ui32SecurityValue; + + // + // Security protection only works if the signature data is correct. + // + iRC = customer_info_signature_set(); + if ( iRC ) + { + return iRC; + } + + // + // Clear the DEBUGGER bit. + // + ui32SecurityValue = AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + ~AM_HAL_FLASH_INFO_SECURITY_DEBUGGERPROT_M; + + // + // Now write the word to the flash INFO space. + // + return g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32SecurityValue, // source data + AM_HAL_FLASH_INFO_SECURITY_O / 4, // word offset + 1 ); // number of words +} + +//***************************************************************************** +// +//! @brief check for debugger disabled. +//! +//! Use this function to determine if the debugger is disabled. +//! +//! @return true if the debugger is disabled, otherwise false. +// +//***************************************************************************** +bool +am_hal_flash_debugger_disable_check(void) +{ + // + // If they are erased at this point then SRAM wipe can't be enabled. + // + if ( customer_info_signature_erased() ) + { + return false; + } + + // + // If they are not vale at this point then SRAM wipe can't be enabled. + // + if ( !am_hal_flash_customer_info_signature_check() ) + { + return false; + } + + // + // Looking good so far, now check the debugger disable bit. + // + return AM_REGVAL(AM_HAL_FLASH_INFO_SECURITY_ADDR) & + AM_HAL_FLASH_INFO_SECURITY_DEBUGGERPROT_M ? false : true; +} + +//***************************************************************************** +// +//! @brief This static helper function generates a 64-bit protection mask. +//! +//! @param pui32StartAddress - Starting address in flash to begin protection. +//! @param pui32StopAddress - Ending address in flash to stop protection. +//! +//! This function computes a chunk map for the protection range. +//! +//! @return Inverse of the actual chunk mask. That is, chunks to be protected +//! are represented as 0 in the returned mask, while chunks to be left alone +//! are represented as 1. This value can therefore be directly ANDed with the +//! existing bits in INFO space. +//! Note that -1 is returned if input parameters are invalid - this return +//! value would indicate that no chunks are to be protected. +//! +// +//***************************************************************************** +static uint64_t +generate_chunk_mask(uint32_t *pui32StartAddress, uint32_t *pui32StopAddress) +{ + uint32_t ui32ChunkStart, ui32ChunkStop; + uint32_t ui32Width; + uint64_t ui64Mask; + + // + // Validate the address input parameters + // + if ( (pui32StartAddress > pui32StopAddress) || + (pui32StopAddress > (uint32_t*)AM_HAL_FLASH_LARGEST_VALID_ADDR) ) + { + // + // Argument error, return value to leave all chunks unprotected. + // + return 0xFFFFFFFFFFFFFFFF; + } + + // + // Extract chunk related information + // + ui32ChunkStart = AM_HAL_FLASH_INFO_ADDR2CHUNK((uint32_t)pui32StartAddress); + ui32ChunkStop = AM_HAL_FLASH_INFO_ADDR2CHUNK((uint32_t)pui32StopAddress); + ui32Width = ui32ChunkStop - ui32ChunkStart + 1; + + if ( ui32Width == 64 ) + { + ui64Mask = (uint64_t)0xFFFFFFFFFFFFFFFFLLU; + } + else + { + ui64Mask = ( ((uint64_t)0x0000000000000001) << ui32Width) - 1; + ui64Mask <<= ui32ChunkStart; + } + + // + // OK now return the chunk mask (inverted). + // + return ~ui64Mask; +} + +//***************************************************************************** +// +//! @brief This function sets copy protection for a range of flash chunks. +//! +//! @param pui32StartAddress - Starting address in flash to begin protection. +//! @param pui32StopAddress - Ending address in flash to stop protection. +//! +//! This function will set copy protection bits for a range of flash chunks +//! +//! @note Each flash chunk contains 16KBytes and corresponds to one bit in +//! the protection register. Set the bit to zero to enable protection. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return +//! 0 for success. +//! 0x400000 if the protection bits were already programmed (mask the return +//! value with 0x3FFFFF to ignore this case and treat as success). +//! Otherwise, non-zero for failure. +// +//***************************************************************************** +int32_t +am_hal_flash_copy_protect_set(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress) +{ + int iRC; + bool bModified = false; + uint64_t ui64Mask; + uint32_t ui32Work; + uint32_t ui32Protection[2]; + uint32_t *pui32Protection = (uint32_t *)AM_HAL_FLASH_INFO_COPYPROT_ADDR; + + // + // Extract chunk mask from parameters. + // Also checks parameter validity (returns -1 if bad parameters). + // + ui64Mask = generate_chunk_mask(pui32StartAddress, pui32StopAddress); + if ( ~ui64Mask == 0x0 ) + { + return 0x100000; + } + + // + // Go get the current settings for copy protection. + // + ui32Protection[0] = pui32Protection[0]; + ui32Protection[1] = pui32Protection[1]; + + // + // AND mask off the necessary protection bits in the lower word. + // + ui32Work = (uint32_t)ui64Mask; + if ( ( ~ui32Work ) && ( ui32Work != ui32Protection[0] ) ) + { + bModified = true; + ui32Protection[0] &= ui32Work; + iRC = g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32Protection[0], // source data + (AM_HAL_FLASH_INFO_COPYPROT_O / 4) + 0, // word offset + 1 ); // number of words + + if ( iRC ) + { + return iRC | 0x10000; + } + } + + // + // AND mask off the necessary protection bits in the upper word. + // + ui32Work = (uint32_t)(ui64Mask >> 32); + if ( ( ~ui32Work ) && ( ui32Work != ui32Protection[1] ) ) + { + bModified = true; + ui32Protection[1] &= ui32Work; + iRC = g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32Protection[1], // source data + (AM_HAL_FLASH_INFO_COPYPROT_O / 4) + 1, // word offset + 1 ); // number of words + + if ( iRC ) + { + return iRC | 0x20000; + } + } + + if ( bModified ) + { + return 0; + } + else + { + return 0x400000; + } +} + +//***************************************************************************** +// +//! @brief This function checks copy protection for a range of flash chunks. +//! +//! @param pui32StartAddress - Starting address in flash. +//! @param pui32StopAddress - Ending address in flash. +//! +//! This function will check copy protection bits for a range of flash chunks +//! it expects all chunks in the range to be protected. +//! +//! @note Each flash chunk contains 16KBytes and corresponds to one bit in +//! the protection register. Set the bit to zero to enable protection. +//! +//! @return false for at least one chunk in the covered range is not protected, +//! and true if all chunks in the covered range are protected. +//! +// +//***************************************************************************** +bool +am_hal_flash_copy_protect_check(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress) +{ + uint64_t ui64Mask; + uint32_t ui32Work; + uint32_t *pui32Protection = (uint32_t *)AM_HAL_FLASH_INFO_COPYPROT_ADDR; + + // + // Extract chunk mask from parameters. + // Also checks parameter validity (returns -1 if bad parameters). + // + ui64Mask = generate_chunk_mask(pui32StartAddress, pui32StopAddress); + if ( ~ui64Mask == 0x0 ) + { + return false; + } + + // + // Now check the lower word of protection bits. + // + ui32Work = (uint32_t)ui64Mask; + if ( ~ui32Work & pui32Protection[0] ) + { + return false; + } + + // + // Now check the lower word of protection bits. + // + ui32Work = (uint32_t)(ui64Mask >> 32); + if ( ~ui32Work & pui32Protection[1] ) + { + return false; + } + + // + // If we get here, there are no unprotected chunks within specified range. + // + return true; +} + +//***************************************************************************** +// +//! @brief This function sets write protection for a range of flash chunks. +//! +//! @param pui32StartAddress - Starting address in flash to begin protection. +//! @param pui32StopAddress - Ending address in flash to stop protection. +//! +//! This function will set write protection bits for a range of flash chunks +//! +//! @note Each flash chunk contains 16KBytes and corresponds to one bit in +//! the protection register. Set the bit to zero to enable protection. +//! +//! @note Interrupts are active during execution of this function. Any interrupt +//! taken could cause execution errors. Please see the IMPORTANT note under +//! Detailed Description above for more details. +//! +//! @return +//! 0 for success. +//! 0x400000 if the protection bits were already programmed (mask the return +//! value with 0x3FFFFF to ignore this case and treat as success). +//! Otherwise, non-zero for failure. +// +//***************************************************************************** +int32_t +am_hal_flash_write_protect_set(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress) +{ + int iRC; + bool bModified = false; + uint64_t ui64Mask; + uint32_t ui32Work; + uint32_t ui32Protection[2]; + uint32_t *pui32Protection = (uint32_t *)AM_HAL_FLASH_INFO_WRITPROT_ADDR; + + // + // Extract chunk mask from parameters. + // Also checks parameter validity (returns -1 if bad parameters). + // + ui64Mask = generate_chunk_mask(pui32StartAddress, pui32StopAddress); + if ( ~ui64Mask == 0x0 ) + { + return 0x100000; + } + + // + // Go get the current settings for copy protection. + // + ui32Protection[0] = pui32Protection[0]; + ui32Protection[1] = pui32Protection[1]; + + // + // AND mask off the necessary protection bits in the lower word. + // + ui32Work = (uint32_t)ui64Mask; + if ( ( ~ui32Work ) && ( ui32Work != ui32Protection[0] ) ) + { + bModified = true; + ui32Protection[0] &= ui32Work; + iRC = g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32Protection[0], // source data + (AM_HAL_FLASH_INFO_WRITPROT_O / 4) + 0, // word offset + 1 ); // number of words + + if ( iRC ) + { + return iRC | 0x10000; + } + } + + // + // AND mask off the necessary protection bits in the upper word. + // + ui32Work = (uint32_t)(ui64Mask >> 32); + if ( ( ~ui32Work ) && ( ui32Work != ui32Protection[1] ) ) + { + bModified = true; + ui32Protection[1] &= ui32Work; + iRC = g_am_hal_flash.flash_program_info( + AM_HAL_FLASH_PROGRAM_KEY, + 0, // instance + &ui32Protection[1], // source data + (AM_HAL_FLASH_INFO_WRITPROT_O / 4) + 1, // word offset + 1 ); // number of words + + if ( iRC ) + { + return iRC | 0x20000; + } + } + + if ( bModified ) + { + return 0; + } + else + { + return 0x400000; + } +} + +//***************************************************************************** +// +//! @brief This function checks write protection for a range of flash chunks. +//! +//! @param pui32StartAddress - Starting address in flash. +//! @param pui32StopAddress - Ending address in flash. +//! +//! This function will check write protection bits for a range of flash chunks +//! it expects all chunks in the range to be protected. +//! +//! @note Each flash chunk contains 16KBytes and corresponds to one bit in +//! the protection register. Set the bit to zero to enable protection. +//! +//! @return false for at least one chunk in the covered range is not protected, +//! and true if all chunks in the covered range are protected. +//! +// +//***************************************************************************** +bool +am_hal_flash_write_protect_check(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress) +{ + uint64_t ui64Mask; + uint32_t ui32Work; + uint32_t *pui32Protection = (uint32_t *)AM_HAL_FLASH_INFO_WRITPROT_ADDR; + + // + // Extract chunk mask from parameters. + // Also checks parameter validity (returns -1 if bad parameters). + // + ui64Mask = generate_chunk_mask(pui32StartAddress, pui32StopAddress); + if ( ~ui64Mask == 0x0 ) + { + return false; + } + + // + // Now check the lower word of protection bits. + // + ui32Work = (uint32_t)ui64Mask; + if ( ~ui32Work & pui32Protection[0] ) + { + return false; + } + + // + // Now check the lower word of protection bits. + // + ui32Work = (uint32_t)(ui64Mask >> 32); + if ( ~ui32Work & pui32Protection[1] ) + { + return false; + } + + // + // If we get here, there are no unprotected chunks within specified range. + // + return true; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_flash.h b/bsp/apollo2/libraries/drivers/hal/am_hal_flash.h new file mode 100644 index 0000000000..66d6f5059c --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_flash.h @@ -0,0 +1,297 @@ +//***************************************************************************** +// +// am_hal_flash.h +//! @file +//! +//! @brief Functions for performing Flash operations. +//! +//! @addtogroup flash2 Flash +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_FLASH_H +#define AM_HAL_FLASH_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +//***************************************************************************** +// +// Flash Program keys. +// +//***************************************************************************** +#define AM_HAL_FLASH_PROGRAM_KEY 0x12344321 +#define AM_HAL_FLASH_RECOVERY_KEY 0xA35C9B6D +#define AM_HAL_FLASH_INFO_KEY 0x12344321 +#define AM_HAL_FLASH_OTP_KEY (AM_HAL_FLASH_INFO_KEY) + +//***************************************************************************** +// +// Some helpful flash values and macros. +// +//***************************************************************************** +#define AM_HAL_FLASH_ADDR 0x00000000 +#define AM_HAL_FLASH_PAGE_SIZE ( 8 * 1024 ) +#define AM_HAL_FLASH_INFO_SIZE AM_HAL_FLASH_PAGE_SIZE +#define AM_HAL_FLASH_INSTANCE_SIZE ( 512 * 1024 ) +#define AM_HAL_FLASH_INSTANCE_PAGES ( AM_HAL_FLASH_INSTANCE_SIZE / AM_HAL_FLASH_PAGE_SIZE ) +#define AM_HAL_FLASH_TOTAL_SIZE ( AM_HAL_FLASH_INSTANCE_SIZE * 2 ) +#define AM_HAL_FLASH_LARGEST_VALID_ADDR ( AM_HAL_FLASH_ADDR + AM_HAL_FLASH_TOTAL_SIZE - 1 ) + +// +// Convert an absolute flash address to a instance +// +#define AM_HAL_FLASH_ADDR2INST(addr) ( ( addr >> 19 ) & 1 ) + +// +// Convert an absolute flash address to a page number relative to the instance +// +#define AM_HAL_FLASH_ADDR2PAGE(addr) ( ( addr >> 13 ) & 0x3F ) + +// +// Convert an absolute flash address to an absolute page number +// +#define AM_HAL_FLASH_ADDR2ABSPAGE(addr) ( addr >> 13 ) + +// +// Given a number of microseconds, convert to a value representing the number of +// cycles that will give that delay. This macro is basically taking into account +// some of the call overhead. +// e.g. To provide a 2us delay: +// am_hal_flash_delay( FLASH_CYCLES_US(2) ); +// +#define FLASH_CYCLES_US(n) ((n * (AM_HAL_CLKGEN_FREQ_MAX_MHZ / 3)) - 4) + +// +// Backward compatibility +// +#define am_hal_flash_program_otp am_hal_flash_program_info +#define am_hal_flash_program_otp_sram am_hal_flash_program_info_sram + +//***************************************************************************** +// +// Structure of function pointers to helper functions for invoking various +// flash operations. The functions we are pointing to here are in the Apollo 2 +// integrated BOOTROM. +// +//***************************************************************************** +typedef struct am_hal_flash_helper_struct +{ + // + // The basics. + // + int (*flash_mass_erase)(uint32_t, uint32_t); + int (*flash_page_erase)(uint32_t, uint32_t, uint32_t); + int (*flash_program_main)(uint32_t, uint32_t *, + uint32_t*, uint32_t); + int (*flash_program_info)(uint32_t, uint32_t, + uint32_t*, uint32_t, uint32_t); + + // + // Non-blocking variants, but be careful these are not interrupt safe so + // mask interrupts while these very long operations proceed. + // + int (*flash_mass_erase_nb)(uint32_t, uint32_t); + int (*flash_page_erase_nb)(uint32_t, uint32_t, uint32_t); + bool (*flash_nb_operation_complete)(void); + + // + // Essentially these are recovery options. + // + int (*flash_erase_info)(uint32_t, uint32_t); + int (*flash_erase_main_plus_info)(uint32_t, uint32_t); + int (*flash_erase_main_plus_info_both_instances)(uint32_t); + void (*flash_recovery)(uint32_t); + + // + // Useful utilities. + // + uint32_t (*flash_util_read_word)(uint32_t*); + void (*flash_util_write_word)(uint32_t*, uint32_t); + void (*delay_cycles)(uint32_t); + + // + // The following functions pointers will generally never be called from + // user programs. They are here primarily to document these entry points + // which are usable from a debugger or debugger script. + // + void (*flash_program_main_sram)(void); + void (*flash_program_info_sram)(void); + void (*flash_erase_main_pages_sram)(void); + void (*flash_mass_erase_sram)(void); + void (*flash_erase_info_sram)(void); + void (*flash_erase_main_plus_info_sram)(void); +} g_am_hal_flash_t; +extern g_am_hal_flash_t g_am_hal_flash; + + +//***************************************************************************** +// +// Define some FLASH INFO SPACE values and macros. +// +//***************************************************************************** +#define AM_HAL_FLASH_INFO_ADDR 0x50020000 +#define AM_HAL_FLASH_INFO_SECURITY_O 0x10 +#define AM_HAL_FLASH_INFO_WRITPROT_O 0x20 +#define AM_HAL_FLASH_INFO_COPYPROT_O 0x30 + +#define AM_HAL_FLASH_INFO_SECURITY_ADDR (AM_HAL_FLASH_INFO_ADDR + AM_HAL_FLASH_INFO_SECURITY_O) +#define AM_HAL_FLASH_INFO_WRITPROT_ADDR (AM_HAL_FLASH_INFO_ADDR + AM_HAL_FLASH_INFO_WRITPROT_O) +#define AM_HAL_FLASH_INFO_COPYPROT_ADDR (AM_HAL_FLASH_INFO_ADDR + AM_HAL_FLASH_INFO_COPYPROT_O) + +// +// Define the customer info signature data (at AM_HAL_FLASH_INFO_ADDR). +// These bits must exist in the customer info space in order for many of the +// security and protection functions to work. +// +#define AM_HAL_FLASH_INFO_SIGNATURE0 0x48EAAD88 +#define AM_HAL_FLASH_INFO_SIGNATURE1 0xC9705737 +#define AM_HAL_FLASH_INFO_SIGNATURE2 0x0A6B8458 +#define AM_HAL_FLASH_INFO_SIGNATURE3 0xE41A9D74 + +// +// Define the customer security bits (at AM_HAL_FLASH_INFO_SECURITY_ADDR) +// +#define AM_HAL_FLASH_INFO_SECURITY_DEBUGGERPROT_S 0 +#define AM_HAL_FLASH_INFO_SECURITY_SWOCTRL_S 1 +#define AM_HAL_FLASH_INFO_SECURITY_SRAMWIPE_S 2 +#define AM_HAL_FLASH_INFO_SECURITY_FLASHWIPE_S 3 +#define AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_S 4 +#define AM_HAL_FLASH_INFO_SECURITY_ENINFOERASE_S 8 +#define AM_HAL_FLASH_INFO_SECURITY_BOOTLOADERSPIN_S 9 + +#define AM_HAL_FLASH_INFO_SECURITY_DEBUGGERPROT_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_DEBUGGERPROT_S)) +#define AM_HAL_FLASH_INFO_SECURITY_SWOCTRL_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_SWOCTRL_S)) +#define AM_HAL_FLASH_INFO_SECURITY_SRAMWIPE_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_SRAMWIPE_S)) +#define AM_HAL_FLASH_INFO_SECURITY_FLASHWIPE_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_FLASHWIPE_S)) +#define AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_M ((uint32_t)(0xF << AM_HAL_FLASH_INFO_SECURITY_ENINFOPRGM_S)) +#define AM_HAL_FLASH_INFO_SECURITY_ENINFOERASE_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_ENINFOERASE_S)) +#define AM_HAL_FLASH_INFO_SECURITY_BOOTLOADERSPIN_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_BOOTLOADERSPIN_S)) +#define AM_HAL_FLASH_INFO_SECURITY_DEEPSLEEP_M ((uint32_t)(0x1 << AM_HAL_FLASH_INFO_SECURITY_BOOTLOADERSPIN_S)) +#define AM_HAL_FLASH_INFO_SECURITY_DEEPSLEEP ((uint32_t)(0x0 << AM_HAL_FLASH_INFO_SECURITY_BOOTLOADERSPIN_S)) + +// +// Protection chunk macros +// AM_HAL_FLASH_INFO_CHUNK2ADDR: Convert a chunk number to an address +// AM_HAL_FLASH_INFO_CHUNK2INST: Convert a chunk number to an instance number +// AM_HAL_FLASH_INFO_ADDR2CHUNK: Convert an address to a chunk number +// +#define AM_HAL_FLASH_INFO_CHUNKSIZE (16*1024) + +#define AM_HAL_FLASH_INFO_CHUNK2ADDR(n) (AM_HAL_FLASH_ADDR + (n << 14)) +#define AM_HAL_FLASH_INFO_CHUNK2INST(n) ((n >> 5) & 1 +#define AM_HAL_FLASH_INFO_ADDR2CHUNK(n) ((n) >> 14) + +//***************************************************************************** +// +// Function prototypes for the helper functions +// +//***************************************************************************** +extern int am_hal_flash_mass_erase(uint32_t ui32Value, uint32_t ui32FlashInst); +extern int am_hal_flash_page_erase(uint32_t ui32Value, uint32_t ui32FlashInst, + uint32_t ui32PageNum); +extern int am_hal_flash_program_main(uint32_t value, uint32_t *pSrc, + uint32_t *pDst, uint32_t NumberOfWords); +extern int am_hal_flash_program_info(uint32_t ui32Value, uint32_t ui32InfoInst, + uint32_t *pui32Src, uint32_t ui32Offset, + uint32_t ui32NumWords); + +// +// Recovery type functions for Customer INFO space. +// +extern int am_hal_flash_erase_info(uint32_t ui32ProgramKey, + uint32_t ui32Instance); +extern int am_hal_flash_erase_main_plus_info(uint32_t ui32ProgramKey, + uint32_t ui32Instance); +extern int am_hal_flash_erase_main_plus_info_both_instances( + uint32_t ui32ProgramKey); +extern void am_hal_flash_recovery(uint32_t ui32RecoveryKey); + +// +// BOOTROM resident reader, writer and delay utility functions. +// +extern uint32_t am_hal_flash_load_ui32(uint32_t ui32Address); +extern void am_hal_flash_store_ui32(uint32_t ui32Address, uint32_t ui32Data); +extern void am_hal_flash_delay(uint32_t ui32Iterations); + +// +// These functions update security/protection bits in the customer INFO blOCK. +// +extern bool am_hal_flash_customer_info_signature_check(void); +extern bool am_hal_flash_info_signature_set(void); +extern int32_t am_hal_flash_info_erase_disable(void); +extern bool am_hal_flash_info_erase_disable_check(void); +extern int32_t am_hal_flash_info_program_disable(uint32_t ui32Mask); +extern uint32_t am_hal_flash_info_program_disable_get(void); +extern int32_t am_hal_flash_wipe_flash_enable(void); +extern bool am_hal_flash_wipe_flash_enable_check(void); +extern int32_t am_hal_flash_wipe_sram_enable(void); +extern bool am_hal_flash_wipe_sram_enable_check(void); +extern int32_t am_hal_flash_swo_disable(void); +extern bool am_hal_flash_swo_disable_check(void); +extern int32_t am_hal_flash_debugger_disable(void); +extern bool am_hal_flash_debugger_disable_check(void); + +extern int32_t am_hal_flash_copy_protect_set(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress); +extern bool am_hal_flash_copy_protect_check(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress); +extern int32_t am_hal_flash_write_protect_set(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress); +extern bool am_hal_flash_write_protect_check(uint32_t *pui32StartAddress, + uint32_t *pui32StopAddress); + + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_FLASH_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_global.c b/bsp/apollo2/libraries/drivers/hal/am_hal_global.c new file mode 100644 index 0000000000..498eb1627a --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_global.c @@ -0,0 +1,59 @@ +//***************************************************************************** +// +// am_hal_global.c +//! @file +//! +//! @brief Locate global variables here. +//! +//! This module contains global variables that are used throughout the HAL. +//! +//! One use in particular is that it uses a global HAL flags variable that +//! contains flags used in various parts of the HAL. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Global Variables +// +//***************************************************************************** +uint32_t volatile g_ui32HALflags = 0x00000000; diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_global.h b/bsp/apollo2/libraries/drivers/hal/am_hal_global.h new file mode 100644 index 0000000000..bb437b198a --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_global.h @@ -0,0 +1,114 @@ +//***************************************************************************** +// +// am_hal_global.h +//! @file +//! +//! @brief Locate all HAL global variables here. +//! +//! This module contains global variables that are used throughout the HAL, +//! but not necessarily those designated as const (which typically end up in +//! flash). Consolidating globals here will make it easier to manage them. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_GLOBAL_H +#define AM_HAL_GLOBAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Macro definitions +// +//***************************************************************************** + +//****************************************************************************** +// +// Macros used to access the bit fields in the flags variable. +// +//****************************************************************************** +#define AM_HAL_FLAGS_BFR(flagnm) \ + ((g_ui32HALflags & AM_HAL_FLAGS_##flagnm##_M) >> AM_HAL_FLAGS_##flagnm##_S) + +#define AM_HAL_FLAGS_BFW(flagnm, value) \ + g_ui32HALflags = ((g_ui32HALflags & (~(AM_HAL_FLAGS_##flagnm##_M))) | \ + ((value << AM_HAL_FLAGS_##flagnm##_S) & (AM_HAL_FLAGS_##flagnm##_M)) ) + +//****************************************************************************** +// +// ITMSKIPENABLEDISABLE - Set when the ITM is not to be disabled. This is +// typically needed by Keil debug.ini. +// +//****************************************************************************** +#define AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_S 0 +#define AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M (1 << AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_S) +#define AM_HAL_FLAGS_ITMSKIPENABLEDISABLE(n) (((n) << AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_S) & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M) + +//****************************************************************************** +// +// ITMBKPT - Breakpoint at the end of itm_enable(), which is needed by +// Keil debug.ini. +// +//****************************************************************************** +#define AM_HAL_FLAGS_ITMBKPT_S 1 +#define AM_HAL_FLAGS_ITMBKPT_M (1 << AM_HAL_FLAGS_ITMBKPT_S) +#define AM_HAL_FLAGS_ITMBKPT(n) (((n) << AM_HAL_FLAGS_ITMBKPT_S) & AM_HAL_FLAGS_ITMBKPT_M) + +//****************************************************************************** +// +// Next available flag or bit field. +// +//****************************************************************************** +#define AM_HAL_FLAGS_NEXTBITFIELD_S 2 +#define AM_HAL_FLAGS_NEXTBITFIELD_M (1 << AM_HAL_FLAGS_NEXTBITFIELD_S) +#define AM_HAL_FLAGS_NEXTBITFIELD(n) (((n) << AM_HAL_FLAGS_NEXTBITFIELD_S) & AM_HAL_FLAGS_NEXTBITFIELD_M) + +//***************************************************************************** +// +// Global Variables extern declarations. +// +//***************************************************************************** +extern volatile uint32_t g_ui32HALflags; + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_GLOBAL_H diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.c b/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.c new file mode 100644 index 0000000000..480118da6b --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.c @@ -0,0 +1,503 @@ +//***************************************************************************** +// +// am_hal_gpio.c +//! @file +//! +//! @brief Functions for interfacing with the GPIO module +//! +//! @addtogroup gpio2 GPIO +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Array of function pointers for handling GPIO interrupts. +// +//***************************************************************************** +am_hal_gpio_handler_t am_hal_gpio_ppfnHandlers[64]; + +//***************************************************************************** +// +//! @brief Read the configuration information for the given pin.. +//! +//! @param ui32GPIONum is the GPIO number whose configuration we want to read. +//! +//! This function reads the PADREG, GPIO CFG, and ALTPAD registers for the +//! given GPIO and returns them in the following format: +//! +//! ( (ALTPAD << 16) | (CFG << 8) | PADREG) +//! +//! This is the same format used by the \e am_hal_gpio_pin_config() +//! function-like macro. +//! +//! @return Pin configuration information. +// +//***************************************************************************** +uint32_t +am_hal_gpio_pin_config_read(uint32_t ui32PinNumber) +{ + uint32_t ui32CfgVal, ui32PadregVal, ui32AltPadVal; + + am_hal_debug_assert_msg(ui32PinNumber <= 63, "Invalid GPIO number."); + + ui32CfgVal = AM_HAL_GPIO_CFG_R(ui32PinNumber); + ui32PadregVal = AM_HAL_GPIO_PADREG_R(ui32PinNumber); + ui32AltPadVal = AM_HAL_GPIO_ALTPADREG_R(ui32PinNumber); + + return ( (ui32CfgVal << CFGVAL_GPIOCFG_S) | + (ui32PadregVal << CFGVAL_PADREG_S) | + (ui32AltPadVal << CFGVAL_ALTPAD_S) ); +} + +//***************************************************************************** +// +//! @brief Get the state of ALL GPIOs from the INPUT READ REGISTER. +//! +//! This function retrieves the state of ALL GPIOs from the INPUT READ +//! REGISTER. +//! +//! @return the state for the requested GPIO or -1 for error. +// +//***************************************************************************** +uint64_t +am_hal_gpio_input_read(void) +{ + // + // Combine upper or lower GPIO words into one 64 bit return value. + // + uint64_t ui64RetVal; + + ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, RDB)) << 32; + ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, RDA)) << 0; + + return ui64RetVal; +} + +//***************************************************************************** +// +//! @brief Get the state of ALL GPIOs from the DATA OUTPUT REGISTER. +//! +//! This function retrieves the state of ALL GPIOs from the DATA OUTPUT +//! REGISTER. +//! +//! @return the state for the requested GPIO or -1 for error. +// +//***************************************************************************** +uint64_t +am_hal_gpio_out_read(void) +{ + // + // Combine upper or lower GPIO words into one 64 bit return value. + // + uint64_t ui64RetVal; + + ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, WTB)) << 32; + ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, WTA)) << 0; + + return ui64RetVal; +} + +//***************************************************************************** +// +//! @brief Gets the state of one GPIO from the DATA ENABLE REGISTER. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function gets the state of one GPIO from the DATA ENABLE REGISTER. +//! +//! @return the current state for the requested GPIO. +// +//***************************************************************************** +uint32_t +am_hal_gpio_out_enable_bit_get(uint32_t ui32BitNum) +{ + // + // Return 0 or 1. + // + + return (AM_HAL_GPIO_EN(ui32BitNum) & AM_HAL_GPIO_EN_M(ui32BitNum)) ? 1 : 0; +} + +//***************************************************************************** +// +//! @brief Gets the state of ALL GPIOs from the DATA ENABLE REGISTER. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function gets the state of all GPIOs from the DATA ENABLE REGISTER. +//! +//! @return the current state for the ALL GPIOs. +// +//***************************************************************************** +uint64_t +am_hal_gpio_out_enable_get(void) +{ + // + // Combine upper or lower GPIO words into one 64 bit return value. + // + uint64_t ui64RetVal; + + ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, ENB)) << 32; + ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, ENA)) << 0; + + return ui64RetVal; +} + +//***************************************************************************** +// +//! @brief Enable selected GPIO Interrupts. +//! +//! @param ui64InterruptMask - GPIOs to enable interrupts on. +//! +//! Use this function to enable the GPIO interrupts. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_gpio_int_enable(uint64_t ui64InterruptMask) +{ + // + // Enable the interrupts. + // + AM_REG(GPIO, INT1EN) |= (ui64InterruptMask >> 32); + AM_REG(GPIO, INT0EN) |= (ui64InterruptMask & 0xFFFFFFFF); +} + +//***************************************************************************** +// +//! @brief Enable selected GPIO Interrupts. +//! +//! Use this function to enable the GPIO interrupts. +//! +//! @return logical or of all enabled interrupts. Use AM_HAL_GPIO_BITx to mask +//! interrupts of interest. +// +//***************************************************************************** +uint64_t +am_hal_gpio_int_enable_get(void) +{ + // + // Return enabled interrupts. + // + uint64_t ui64RetVal; + + ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, INT1EN)) << 32; + ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, INT0EN)) << 0; + + return ui64RetVal; +} + +//***************************************************************************** +// +//! @brief Disable selected GPIO Interrupts. +//! +//! @param ui64InterruptMask - GPIOs to disable interrupts on. +//! +//! Use this function to disable the GPIO interrupts. +//! +//! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_gpio_int_disable(uint64_t ui64InterruptMask) +{ + // + // Disable the interrupts. + // + AM_CRITICAL_BEGIN_ASM + AM_REG(GPIO, INT1EN) &= ~(ui64InterruptMask >> 32); + AM_REG(GPIO, INT0EN) &= ~(ui64InterruptMask & 0xFFFFFFFF); + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +//! @brief Clear selected GPIO Interrupts. +//! +//! @param ui64InterruptMask - GPIOs to clear interrupts on. +//! +//! Use this function to clear the GPIO interrupts. +//! +//! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_gpio_int_clear(uint64_t ui64InterruptMask) +{ + // + // Clear the interrupts. + // + AM_CRITICAL_BEGIN_ASM + AM_REG(GPIO, INT1CLR) = (ui64InterruptMask >> 32); + AM_REG(GPIO, INT0CLR) = (ui64InterruptMask & 0xFFFFFFFF); + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +//! @brief Set selected GPIO Interrupts. +//! +//! @param ui64InterruptMask - GPIOs to set interrupts on. +//! +//! Use this function to set the GPIO interrupts. +//! +//! ui64InterruptMask should be a logical or of AM_HAL_GPIO_BITx defines. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_gpio_int_set(uint64_t ui64InterruptMask) +{ + // + // Set the interrupts. + // + AM_REG(GPIO, INT1SET) = (ui64InterruptMask >> 32); + AM_REG(GPIO, INT0SET) = (ui64InterruptMask & 0xFFFFFFFF); +} + +//***************************************************************************** +// +//! @brief Set selected GPIO Interrupts. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! Use this function to set the GPIO interrupts. +//! +//! @return None +// +//***************************************************************************** +uint64_t +am_hal_gpio_int_status_get(bool bEnabledOnly) +{ + uint64_t ui64RetVal, ui64Mask; + + // + // Combine upper or lower GPIO words into one 64 bit return value. + // + ui64Mask = 0xFFFFFFFFFFFFFFFF; + + AM_CRITICAL_BEGIN_ASM + ui64RetVal = ((uint64_t) AM_REGn(GPIO, 0, INT1STAT)) << 32; + ui64RetVal |= ((uint64_t) AM_REGn(GPIO, 0, INT0STAT)) << 0; + + if ( bEnabledOnly ) + { + ui64Mask = ((uint64_t) AM_REGn(GPIO, 0, INT1EN)) << 32; + ui64Mask |= ((uint64_t) AM_REGn(GPIO, 0, INT0EN)) << 0; + } + + ui64RetVal &= ui64Mask; + AM_CRITICAL_END_ASM + + return ui64RetVal; +} + +//***************************************************************************** +// +//! @brief Convenience function for responding to pin interrupts. +//! +//! @param ui64Status is the interrupt status as returned by +//! am_hal_gpio_int_status_get() +//! +//! This function may be called from am_hal_gpio_isr() to read the status of +//! the GPIO interrupts, determine which pin(s) caused the most recent +//! interrupt, and call an interrupt handler function to respond. The interrupt +//! handler to be called must be first registered with the +//! am_hal_gpio_int_register() function. +//! +//! In the event that multiple GPIO interrupts are active, the corresponding +//! interrupt handlers will be called in numerical order by GPIO number +//! starting with the lowest GPIO number. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_gpio_int_service(uint64_t ui64Status) +{ + uint32_t ui32Status; + uint32_t ui32Clz; + + am_hal_gpio_handler_t pfnHandler; + + // + // Handle any active interrupts in the lower 32 bits + // + ui32Status = (uint32_t) ui64Status; + while ( ui32Status ) + { + // + // Pick one of any remaining active interrupt bits + // +#ifdef __IAR_SYSTEMS_ICC__ + ui32Clz = __CLZ(ui32Status); +#else + ui32Clz = __builtin_clz(ui32Status); +#endif + + // + // Turn off the bit we picked in the working copy + // + ui32Status &= ~(0x80000000 >> ui32Clz); + + // + // Check the bit handler table to see if there is an interrupt handler + // registered for this particular bit. + // + pfnHandler = am_hal_gpio_ppfnHandlers[31 - ui32Clz]; + if ( pfnHandler ) + { + // + // If we found an interrupt handler routine, call it now. + // + pfnHandler(); + } + } + + // + // Handle any active interrupts in the upper 32 bits + // + ui32Status = (uint32_t) (ui64Status >> 32); + while ( ui32Status ) + { + // + // Pick one of any remaining active interrupt bits + // +#ifdef __IAR_SYSTEMS_ICC__ + ui32Clz = __CLZ(ui32Status); +#else + ui32Clz = __builtin_clz(ui32Status); +#endif + + // + // Turn off the bit we picked in the working copy + // + ui32Status &= ~(0x80000000 >> ui32Clz); + + // + // Check the bit handler table to see if there is an interrupt handler + // registered for this particular bit. + // + pfnHandler = am_hal_gpio_ppfnHandlers[63 - ui32Clz]; + if ( pfnHandler ) + { + // + // If we found an interrupt handler routine, call it now. + // + pfnHandler(); + } + } +} + +//***************************************************************************** +// +//! @brief Register an interrupt handler for an individual GPIO pin. +//! +//! @param ui32GPIONumber - GPIO number to assign this interrupt handler to. +//! @param pfnHandler - Function to call when this GPIO interrupt is received. +//! +//! This function allows the caller to specify a function that should be called +//! any time a GPIO interrupt is received on a particular pin. Registering an +//! interrupt handler using this function adds the function pointer to an array +//! in SRAM. This interrupt handler will be called by am_hal_gpio_int_service() +//! whenever the ui64Status parameter indicates that the corresponding pin is +//! asserting it's interrupt. +//! +//! To remove an interrupt handler that has already been registered, the +//! pfnHandler parameter may be set to zero. +//! +//! @note This function will not have any effect unless the +//! am_hal_gpio_int_service() function is being used. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_gpio_int_register(uint32_t ui32GPIONumber, + am_hal_gpio_handler_t pfnHandler) +{ + // + // Check to make sure the GPIO number is valid. (Debug builds only) + // + am_hal_debug_assert_msg(ui32GPIONumber < 64, "GPIO number out of range."); + + am_hal_gpio_ppfnHandlers[ui32GPIONumber] = pfnHandler; +} + +//***************************************************************************** +// +//! @brief Get the state of one GPIO polarity bit. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function gets the state of one GPIO polarity bit. +//! +//! @note When the bit is a one the interrupt polarity is rising edge. +//! +//! @return the current polarity. +// +//***************************************************************************** +bool +am_hal_gpio_int_polarity_bit_get(uint32_t ui32BitNum) +{ + // + // Check the GPIO_CFGx register's interrupt polarity bit corresponding to + // this pin number. + // + return (AM_REGVAL(AM_HAL_GPIO_CFG(ui32BitNum)) & + AM_HAL_GPIO_POL_M(ui32BitNum)); +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.h b/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.h new file mode 100644 index 0000000000..60e5cf36d6 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_gpio.h @@ -0,0 +1,684 @@ +//***************************************************************************** +// +// am_hal_gpio.h +//! @file +//! +//! @brief Functions for accessing and configuring the GPIO module. +//! +//! @addtogroup gpio2 GPIO +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_GPIO_H +#define AM_HAL_GPIO_H + +// DEVICE ADDRESS IS 8-bits +#define AM_HAL_GPIO_DEV_ADDR_8 (0) + +// DEVICE ADDRESS IS 16-bits +#define AM_HAL_GPIO_DEV_ADDR_16 (1) + +// DEVICE OFFSET IS 8-bits +#define AM_HAL_GPIO_DEV_OFFSET_8 (0x00000000) + +// DEVICE OFFSET IS 16-bits +#define AM_HAL_GPIO_DEV_OFFSET_16 (0x00010000) + +// Maximum number of GPIOs on this device +#define AM_HAL_GPIO_MAX_PADS (50) + +//***************************************************************************** +// +//! @name GPIO Pin defines +//! @brief GPIO Pin defines for use with interrupt functions +//! +//! These macros may be used to with \e am_hal_gpio_int_x(). +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_GPIO_BIT(n) (((uint64_t) 0x1) << n) +//! @} + +// +// Helper macros used for unraveling the GPIO configuration value (configval). +// +// Note that the configval, which is passed into functions such as +// am_hal_gpio_pin_config() as well as various helper macros, is a concatenated +// value that contains values used in multiple configuration registers. +// +// The GPIO configuration value fields are arranged as follows: +// [ 7: 0] PADREG configuration. +// [11: 8] GPIOCFG +// [15:12] Unused. +// [23:16] ALTPADREG configuration. +// +// Define macros describing these configval fields. +// +#define CFGVAL_PADREG_S 0 +#define CFGVAL_PADREG_M (0xFF << CFGVAL_PADREG_S) +#define CFGVAL_GPIOCFG_S 8 +#define CFGVAL_GPIOCFG_M (0x0F << CFGVAL_GPIOCFG_S) +#define CFGVAL_ALTPAD_S 16 +#define CFGVAL_ALTPAD_M (0xFF << CFGVAL_ALTPAD_S) + +// +// Extraction macros +// +#define CFGVAL_PADREG_X(x) (((uint32_t)(x) & CFGVAL_PADREG_M) >> \ + CFGVAL_PADREG_S) +#define CFGVAL_GPIOCFG_X(x) (((uint32_t)(x) & CFGVAL_GPIOCFG_M) >> \ + CFGVAL_GPIOCFG_S) +#define CFGVAL_ALTPAD_X(x) (((uint32_t)(x) & CFGVAL_ALTPAD_M) >> \ + CFGVAL_ALTPAD_S) + +//***************************************************************************** +// +// Input options. +// +//***************************************************************************** +#define AM_HAL_GPIO_INPEN (0x02 << CFGVAL_PADREG_S) // Enable input transistors. +#define AM_HAL_GPIO_INCFG_RDZERO (0x01 << CFGVAL_GPIOCFG_S) // Disable input read registers. + +//***************************************************************************** +// +// Output options +// +//***************************************************************************** +#define AM_HAL_GPIO_OUT_DISABLE ((0x0 << 1) << CFGVAL_GPIOCFG_S) +#define AM_HAL_GPIO_OUT_PUSHPULL ((0x1 << 1) << CFGVAL_GPIOCFG_S) +#define AM_HAL_GPIO_OUT_OPENDRAIN ((0x2 << 1) << CFGVAL_GPIOCFG_S) +#define AM_HAL_GPIO_OUT_3STATE ((0x3 << 1) << CFGVAL_GPIOCFG_S) + +//***************************************************************************** +// +// Pad configuration options. +// (Configuration value bits 7:0.) +// +//***************************************************************************** +#define AM_HAL_GPIO_HIGH_DRIVE (0x04 << CFGVAL_PADREG_S) +#define AM_HAL_GPIO_LOW_DRIVE (0x00 << CFGVAL_PADREG_S) +#define AM_HAL_GPIO_PULLUP (0x01 << CFGVAL_PADREG_S) +#define AM_HAL_GPIO_PULL1_5K ( (0x01 << CFGVAL_PADREG_S) | \ + AM_HAL_GPIO_PULLUP ) +#define AM_HAL_GPIO_PULL6K ( (0x40 << CFGVAL_PADREG_S) | \ + AM_HAL_GPIO_PULLUP ) +#define AM_HAL_GPIO_PULL12K ( (0x80 << CFGVAL_PADREG_S) | \ + AM_HAL_GPIO_PULLUP ) +#define AM_HAL_GPIO_PULL24K ( (0xC0 << CFGVAL_PADREG_S) | \ + AM_HAL_GPIO_PULLUP ) + +// POWER SWITCH is available on selected pins +#define AM_HAL_GPIO_POWER (0x80 << CFGVAL_PADREG_S) + +//***************************************************************************** +// +//! ALTPADREG configuration options. +//! (Configuration value bits 23:16.) +//! +//! All Apollo2 GPIO pins can be configured for 2mA or 4mA. +//! AM_HAL_GPIO_DRIVE_2MA = 2mA configuration. +//! AM_HAL_GPIO_DRIVE_4MA = 4mA configuration. +//! +//! Certain Apollo2 GPIO pins can be configured to drive up to 12mA. +//! AM_HAL_GPIO_DRIVE_8MA = 8mA configuration. +//! AM_HAL_GPIO_DRIVE_12MA = 12mA configuration. +//! +//! Notes: +//! - Always consult the Apollo2 data sheet for the latest details. +//! - The higher drive GPIOxx pads generally include: +//! 0-2,5,7-8,10,12-13,22-23,26-29,38-39,42,44-48. +//! - GPIOxx pads that do not support the higher drive: +//! 3-4,6,9,11,14-21,24-25,30-37,40-41,43,49. +//! - User is responsible for ensuring that the selected pin actually supports +//! the higher drive (8mA or 12mA) capabilities. See the Apollo2 data sheet. +//! - Attempting to set the higher drive (8mA or 12mA) configuration on a +//! non-supporting pad will actually set the pad for 4mA drive strength, +//! regardless of the lower bit setting. +// +//***************************************************************************** +#define AM_HAL_GPIO_DRIVE_2MA ( 0 ) +#define AM_HAL_GPIO_DRIVE_4MA AM_HAL_GPIO_HIGH_DRIVE +#define AM_HAL_GPIO_DRIVE_8MA ( 0x01 << CFGVAL_ALTPAD_S ) +#define AM_HAL_GPIO_DRIVE_12MA ( (0x01 << CFGVAL_ALTPAD_S) | \ + AM_HAL_GPIO_HIGH_DRIVE ) + +#define AM_HAL_GPIO_SLEWRATE ( 0x10 << CFGVAL_ALTPAD_S ) + +//***************************************************************************** +// +// Interrupt polarity +// These values can be used directly in the configval. +// +//***************************************************************************** +#define AM_HAL_GPIOCFGVAL_FALLING ((1 << 2) << CFGVAL_GPIOCFG_S) +#define AM_HAL_GPIOCFGVAL_RISING ((0 << 2) << CFGVAL_GPIOCFG_S) + +//***************************************************************************** +// +// Pad function select +// This macro represents the 3 bit function select field in the PADREG byte. +// +//***************************************************************************** +#define AM_HAL_GPIO_FUNC(x) ((x & 0x7) << 3) + +//***************************************************************************** +// +//! Interrupt polarity +//! +//! Important: +//! These values are to be used with am_hal_gpio_int_polarity_bit_set(). +// They are not intended to be used as part of the GPIO configval. +// +//***************************************************************************** +#define AM_HAL_GPIO_FALLING 0x00000001 +#define AM_HAL_GPIO_RISING 0x00000000 + +//***************************************************************************** +// +// A few common pin configurations. +// +//***************************************************************************** +#define AM_HAL_GPIO_DISABLE \ + (AM_HAL_GPIO_FUNC(3)) + +#define AM_HAL_GPIO_INPUT \ + (AM_HAL_GPIO_FUNC(3) | AM_HAL_GPIO_INPEN) + +#define AM_HAL_GPIO_OUTPUT \ + (AM_HAL_GPIO_FUNC(3) | AM_HAL_GPIO_OUT_PUSHPULL) + +#define AM_HAL_GPIO_OPENDRAIN \ + (AM_HAL_GPIO_FUNC(3) | AM_HAL_GPIO_OUT_OPENDRAIN | AM_HAL_GPIO_INPEN) + +#define AM_HAL_GPIO_3STATE \ + (AM_HAL_GPIO_FUNC(3) | AM_HAL_GPIO_OUT_3STATE) + +//***************************************************************************** +// +// PADREG helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_PADREG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_PADREGA_O + (n & 0xFC)) + +#define AM_HAL_GPIO_PADREG_S(n) \ + (((uint32_t)(n) % 4) << 3) + +#define AM_HAL_GPIO_PADREG_M(n) \ + ((uint32_t) 0xFF << AM_HAL_GPIO_PADREG_S(n)) + +#define AM_HAL_GPIO_PADREG_FIELD(n, configval) \ + (((uint32_t)(configval) & CFGVAL_PADREG_M) << AM_HAL_GPIO_PADREG_S(n)) + +#define AM_HAL_GPIO_PADREG_W(n, configval) \ + AM_REGVAL(AM_HAL_GPIO_PADREG(n)) = \ + (AM_HAL_GPIO_PADREG_FIELD(n, configval) | \ + (AM_REGVAL(AM_HAL_GPIO_PADREG(n)) & ~AM_HAL_GPIO_PADREG_M(n))) + +#define AM_HAL_GPIO_PADREG_R(n) \ + ((AM_REGVAL(AM_HAL_GPIO_PADREG(n)) & AM_HAL_GPIO_PADREG_M(n)) >> \ + AM_HAL_GPIO_PADREG_S(n)) + + +//***************************************************************************** +// +// ALTPADCFG helper macros. +// The ALTPADCFG bits are located in [23:16] of the configval. +// +//***************************************************************************** +#define AM_HAL_GPIO_ALTPADREG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_ALTPADCFGA_O + (n & 0xFC)) + +#define AM_HAL_GPIO_ALTPADREG_S(n) \ + (((uint32_t)(n) % 4) << 3) + +#define AM_HAL_GPIO_ALTPADREG_M(n) \ + ((uint32_t) 0xFF << AM_HAL_GPIO_ALTPADREG_S(n)) + +#define AM_HAL_GPIO_ALTPADREG_FIELD(n, configval) \ + (CFGVAL_ALTPAD_X(configval) << AM_HAL_GPIO_ALTPADREG_S(n)) + +#define AM_HAL_GPIO_ALTPADREG_W(n, configval) \ + AM_REGVAL(AM_HAL_GPIO_ALTPADREG(n)) = \ + (AM_HAL_GPIO_ALTPADREG_FIELD(n, configval) | \ + (AM_REGVAL(AM_HAL_GPIO_ALTPADREG(n)) & ~AM_HAL_GPIO_ALTPADREG_M(n))) + +#define AM_HAL_GPIO_ALTPADREG_R(n) \ + ((AM_REGVAL(AM_HAL_GPIO_ALTPADREG(n)) & AM_HAL_GPIO_ALTPADREG_M(n)) >> \ + AM_HAL_GPIO_ALTPADREG_S(n)) + +//***************************************************************************** +// +// CFG helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_CFG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_CFGA_O + ((n & 0xF8) >> 1)) + +#define AM_HAL_GPIO_CFG_S(n) \ + (((uint32_t)(n) % 8) << 2) + +#define AM_HAL_GPIO_CFG_M(n) \ + ((uint32_t) 0x7 << AM_HAL_GPIO_CFG_S(n)) + +#define AM_HAL_GPIO_CFG_FIELD(n, configval) \ + ((((uint32_t)(configval) & 0x700) >> 8) << AM_HAL_GPIO_CFG_S(n)) + +#define AM_HAL_GPIO_CFG_W(n, configval) \ + AM_REGVAL(AM_HAL_GPIO_CFG(n)) = \ + (AM_HAL_GPIO_CFG_FIELD(n, configval) | \ + (AM_REGVAL(AM_HAL_GPIO_CFG(n)) & ~AM_HAL_GPIO_CFG_M(n))) + +#define AM_HAL_GPIO_CFG_R(n) \ + ((AM_REGVAL(AM_HAL_GPIO_CFG(n)) & AM_HAL_GPIO_CFG_M(n)) >> \ + AM_HAL_GPIO_CFG_S(n)) + +//***************************************************************************** +// +// Polarity helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_POL_S(n) \ + ((((uint32_t)(n) % 8) << 2) + 3) + +#define AM_HAL_GPIO_POL_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_POL_S(n)) + +#define AM_HAL_GPIO_POL_FIELD(n, polarity) \ + (((uint32_t)(polarity) & 0x1) << AM_HAL_GPIO_POL_S(n)) + +#define AM_HAL_GPIO_POL_W(n, polarity) \ + AM_REGVAL(AM_HAL_GPIO_CFG(n)) = \ + (AM_HAL_GPIO_POL_FIELD(n, polarity) | \ + (AM_REGVAL(AM_HAL_GPIO_CFG(n)) & ~AM_HAL_GPIO_POL_M(n))) + +//***************************************************************************** +// +// RD helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_RD_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_RDA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_RD_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_RD_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_RD_S(n)) + +#define AM_HAL_GPIO_RD(n) \ + AM_REGVAL(AM_HAL_GPIO_RD_REG(n)) + +//***************************************************************************** +// +// WT helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_WT_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_WTA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_WT_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_WT_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_WT_S(n)) + +#define AM_HAL_GPIO_WT(n) \ + AM_REGVAL(AM_HAL_GPIO_WT_REG(n)) + +//***************************************************************************** +// +// WTS helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_WTS_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_WTSA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_WTS_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_WTS_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_WTS_S(n)) + +#define AM_HAL_GPIO_WTS(n) \ + AM_REGVAL(AM_HAL_GPIO_WTS_REG(n)) + +//***************************************************************************** +// +// WTC helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_WTC_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_WTCA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_WTC_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_WTC_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_WTC_S(n)) + +#define AM_HAL_GPIO_WTC(n) \ + AM_REGVAL(AM_HAL_GPIO_WTC_REG(n)) + +//***************************************************************************** +// +// EN helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_EN_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_ENA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_EN_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_EN_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_EN_S(n)) + +#define AM_HAL_GPIO_EN(n) \ + AM_REGVAL(AM_HAL_GPIO_EN_REG(n)) + +//***************************************************************************** +// +// ENS helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_ENS_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_ENSA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_ENS_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_ENS_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_ENS_S(n)) + +#define AM_HAL_GPIO_ENS(n) \ + AM_REGVAL(AM_HAL_GPIO_ENS_REG(n)) + +//***************************************************************************** +// +// ENC helper macros. +// +//***************************************************************************** +#define AM_HAL_GPIO_ENC_REG(n) \ + (AM_REG_GPIOn(0) + AM_REG_GPIO_ENCA_O + (((uint32_t)(n) & 0x20) >> 3)) + +#define AM_HAL_GPIO_ENC_S(n) \ + ((uint32_t)(n) % 32) + +#define AM_HAL_GPIO_ENC_M(n) \ + ((uint32_t) 0x1 << AM_HAL_GPIO_ENC_S(n)) + +#define AM_HAL_GPIO_ENC(n) \ + AM_REGVAL(AM_HAL_GPIO_ENC_REG(n)) + +//***************************************************************************** +// +//! @brief Configure the GPIO PAD MUX & GPIO PIN Configurations +//! +//! @param ui32PinNumber - GPIO pin number. +//! @param ui32Config - Configuration options. +//! +//! This function applies the settings for a single GPIO. For a list of valid +//! options please see the top of this file (am_hal_gpio.h) and am_hal_pin.h. +//! +//! Usage examples: +//! am_hal_gpio_pin_config(11, AM_HAL_GPIO_INPUT); +//! am_hal_gpio_pin_config(10, AM_HAL_GPIO_OUTPUT); +//! am_hal_gpio_pin_config(14, AM_HAL_GPIO_OUTPUT | AM_HAL_GPIO_SLEWRATE); +//! am_hal_gpio_pin_config(15, AM_HAL_GPIO_OUTPUT | AM_HAL_GPIO_HIGHDRIVESTR); +// +//***************************************************************************** +#define am_hal_gpio_pin_config(ui32PinNumber, ui32Config) \ + if ( (uint32_t)(ui32PinNumber) < AM_HAL_GPIO_MAX_PADS ) \ + { \ + AM_CRITICAL_BEGIN_ASM \ + \ + AM_REGn(GPIO, 0, PADKEY) = AM_REG_GPIO_PADKEY_KEYVAL; \ + \ + AM_HAL_GPIO_CFG_W(ui32PinNumber, ui32Config); \ + AM_HAL_GPIO_PADREG_W(ui32PinNumber, ui32Config); \ + AM_HAL_GPIO_ALTPADREG_W(ui32PinNumber, ui32Config); \ + \ + AM_REGn(GPIO, 0, PADKEY) = 0; \ + \ + AM_CRITICAL_END_ASM \ + } + +//***************************************************************************** +// +//! @brief Set the state of one GPIO polarity bit. +//! +//! @param ui32BitNum - GPIO number. +//! @param ui32Polarity - Desired state. +//! +//! This function sets the state of one GPIO polarity bit to a supplied value. +//! The ui32Polarity parameter should be one of the following values: +//! +//! AM_HAL_GPIO_FALLING +//! AM_HAL_GPIO_RISING +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_int_polarity_bit_set(ui32PinNumber, ui32Polarity) \ + if ( (uint32_t)(ui32PinNumber) < AM_HAL_GPIO_MAX_PADS ) \ + { \ + AM_CRITICAL_BEGIN_ASM \ + \ + AM_REGn(GPIO, 0, PADKEY) = AM_REG_GPIO_PADKEY_KEYVAL; \ + AM_HAL_GPIO_POL_W(ui32PinNumber, ui32Polarity); \ + AM_REGn(GPIO, 0, PADKEY) = 0; \ + \ + AM_CRITICAL_END_ASM \ + } + +//***************************************************************************** +// +//! @brief Get the state of one GPIO from the INPUT READ REGISTER. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function retrieves the state of one GPIO from the INPUT READ +//! REGISTER. +//! +//! @return the state for the requested GPIO. +// +//***************************************************************************** +#define am_hal_gpio_input_bit_read(ui32BitNum) \ + ((AM_HAL_GPIO_RD(ui32BitNum) & AM_HAL_GPIO_RD_M(ui32BitNum)) != 0) + +//***************************************************************************** +// +//! @brief Get the state of one GPIO in the DATA OUTPUT REGISTER +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function retrieves the state of one GPIO in the DATA OUTPUT REGISTER. +//! +//! @return the state for the requested GPIO or -1 for error. +// +//***************************************************************************** +#define am_hal_gpio_out_bit_read(ui32BitNum) \ + ((AM_HAL_GPIO_WT(ui32BitNum) & AM_HAL_GPIO_WT_M(ui32BitNum)) != 0) + +//***************************************************************************** +// +//! @brief Set the output state high for one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function sets the output state to high for one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_bit_set(ui32BitNum) \ + AM_HAL_GPIO_WTS(ui32BitNum) = AM_HAL_GPIO_WTS_M(ui32BitNum) + +//***************************************************************************** +// +//! @brief Sets the output state to low for one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function sets the output state to low for one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_bit_clear(ui32BitNum) \ + AM_HAL_GPIO_WTC(ui32BitNum) = AM_HAL_GPIO_WTC_M(ui32BitNum) + +//***************************************************************************** +// +//! @brief Sets the output state to ui32Value for one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! @param ui32Value - Desired output state. +//! +//! This function sets the output state to ui32Value for one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_bit_replace(ui32BitNum, ui32Value) \ + if ( ui32Value ) \ + { \ + AM_HAL_GPIO_WTS(ui32BitNum) = AM_HAL_GPIO_WTS_M(ui32BitNum); \ + } \ + else \ + { \ + AM_HAL_GPIO_WTC(ui32BitNum) = AM_HAL_GPIO_WTC_M(ui32BitNum); \ + } + +//***************************************************************************** +// +//! @brief Toggle the output state of one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function toggles the output state of one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_bit_toggle(ui32BitNum) \ + if ( 1 ) \ + { \ + AM_CRITICAL_BEGIN_ASM \ + AM_HAL_GPIO_WT(ui32BitNum) ^= AM_HAL_GPIO_WT_M(ui32BitNum); \ + AM_CRITICAL_END_ASM \ + } + +//***************************************************************************** +// +//! @brief Sets the output enable for one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function sets the output enable for one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_enable_bit_set(ui32BitNum) \ + AM_HAL_GPIO_ENS(ui32BitNum) = AM_HAL_GPIO_ENS_M(ui32BitNum) + +//***************************************************************************** +// +//! @brief Clears the output enable for one GPIO. +//! +//! @param ui32BitNum - GPIO number. +//! +//! This function clears the output enable for one GPIO. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_gpio_out_enable_bit_clear(ui32BitNum) \ + AM_HAL_GPIO_ENC(ui32BitNum) = AM_HAL_GPIO_ENC_M(ui32BitNum) + +//***************************************************************************** +// +// Function pointer type for GPIO interrupt handlers. +// +//***************************************************************************** +typedef void (*am_hal_gpio_handler_t)(void); + +//***************************************************************************** +// +// External function prototypes +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +extern uint32_t am_hal_gpio_pin_config_read(uint32_t ui32PinNumber); +extern uint64_t am_hal_gpio_input_read(void); +extern uint64_t am_hal_gpio_out_read(void); +extern uint32_t am_hal_gpio_out_enable_bit_get(uint32_t ui32BitNum); +extern uint64_t am_hal_gpio_out_enable_get(void); +extern void am_hal_gpio_int_enable(uint64_t ui64InterruptMask); +extern uint64_t am_hal_gpio_int_enable_get(void); +extern void am_hal_gpio_int_disable(uint64_t ui64InterruptMask); +extern void am_hal_gpio_int_clear(uint64_t ui64InterruptMask); +extern void am_hal_gpio_int_set(uint64_t ui64InterruptMask); +extern uint64_t am_hal_gpio_int_status_get(bool bEnabledOnly); +extern void am_hal_gpio_int_service(uint64_t ui64Status); +extern void am_hal_gpio_int_register(uint32_t ui32GPIONumber, + am_hal_gpio_handler_t pfnHandler); + +extern bool am_hal_gpio_int_polarity_bit_get(uint32_t ui32BitNum); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_GPIO_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.c b/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.c new file mode 100644 index 0000000000..603dd8c4ec --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.c @@ -0,0 +1,757 @@ +//***************************************************************************** +// +// am_hal_i2c_bit_bang.c +//! @file +//! +//! @brief I2C bit bang module. +//! +//! These functions implement the I2C bit bang utility +//! It implements an I2C interface at close to 400 kHz +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include + +#include "am_mcu_apollo.h" +#include "am_util.h" +#include "am_hal_i2c_bit_bang.h" + +// Max number of clock cycles to wait for clock stretch +#define I2C_BB_MAX_CLOCK_STRETCH_WAIT 100 + +#define I2C_BB_DESIRED_FREQ_HZ 400000 + +#define I2C_BB_CYCLES_PER_DELAY_COUNT 3 +#define I2C_BB_ONE_BIT_TIME_IN_CYCLES (AM_HAL_CLKGEN_FREQ_MAX_HZ/I2C_BB_DESIRED_FREQ_HZ) +#define I2C_BB_ONE_BIT_TIME_IN_DELAY_COUNT (I2C_BB_ONE_BIT_TIME_IN_CYCLES/I2C_BB_CYCLES_PER_DELAY_COUNT) + +// Number of loops (each worth 3 cycles) needed to delay for defined time +// This is imprecise, as there is a setup time as well which is not accounted +// for +// One Bit time = 120 Cycles (400 kHz @ 48 MHz) +#define HALF_BIT_TIME (I2C_BB_ONE_BIT_TIME_IN_DELAY_COUNT/2) +#define QUARTER_BIT_TIME (I2C_BB_ONE_BIT_TIME_IN_DELAY_COUNT/4) +#define ASM_DELAY am_hal_flash_delay + +// Empirically determined adjustments to account for the fact that there is a +// variable time spent in actual processing as well, and hence we need not delay +// for the full time. This processing time is variable based on exact processing +// needed at various times, and will also vary based on compiler type and +// optimization levels +#define I2C_BB_TIMER_ADJUST 6 // Can not be more than QUARTER_BIT_TIME - 1 +#define I2C_BB_TIMER_HI_ADJUST 15 // Can not be more than HALF_BIT_TIME - 1 +#define I2C_BB_TIMER_LO_ADJUST 13 // Can not be more than HALF_BIT_TIME - 1 + +// Wait till it is time to end the SCL Hi Period +#define WAIT_I2C_CLOCK_HI_PERIOD() ASM_DELAY(HALF_BIT_TIME - I2C_BB_TIMER_HI_ADJUST) +// Wait till it is time to end the SCL Lo Period +#define WAIT_I2C_CLOCK_LOW_PERIOD() ASM_DELAY(HALF_BIT_TIME - I2C_BB_TIMER_LO_ADJUST) +// Delay for Quarter Clock +#define WAIT_FOR_QUARTER_I2C_CLOCK() ASM_DELAY(QUARTER_BIT_TIME - I2C_BB_TIMER_ADJUST) +#define WRITE_SCL_LO() \ + do { \ + AM_REGVAL(am_hal_i2c_bit_bang_priv.sck_reg_clr_addr) = (am_hal_i2c_bit_bang_priv.sck_reg_val); \ + } while(0) + +#define PULL_SCL_HI() \ + do { \ + AM_REGVAL(am_hal_i2c_bit_bang_priv.sck_reg_set_addr) = (am_hal_i2c_bit_bang_priv.sck_reg_val); \ + } while(0) + +#define GET_SCL() (AM_REGVAL(am_hal_i2c_bit_bang_priv.sck_reg_read_addr) & (am_hal_i2c_bit_bang_priv.sck_reg_val)) +#define GET_SDA() (AM_REGVAL(am_hal_i2c_bit_bang_priv.sda_reg_read_addr) & (am_hal_i2c_bit_bang_priv.sda_reg_val)) + +#define WRITE_SDA_LO() \ + do { \ + AM_REGVAL(am_hal_i2c_bit_bang_priv.sda_reg_clr_addr) = (am_hal_i2c_bit_bang_priv.sda_reg_val); \ + } while(0) + +#define PULL_SDA_HI() \ + do { \ + AM_REGVAL(am_hal_i2c_bit_bang_priv.sda_reg_set_addr) = (am_hal_i2c_bit_bang_priv.sda_reg_val); \ + } while(0) + + +//***************************************************************************** +// +// I2C Bit Bang Private Data Structure +// +//***************************************************************************** +typedef struct am_util_bit_bang_priv +{ + bool start_flag; + uint32_t sck_gpio_number; + uint32_t sda_gpio_number; + uint32_t sck_reg_set_addr; + uint32_t sck_reg_clr_addr; + uint32_t sck_reg_read_addr; + uint32_t sck_reg_val; + uint32_t sda_reg_set_addr; + uint32_t sda_reg_clr_addr; + uint32_t sda_reg_read_addr; + uint32_t sda_reg_val; +} am_hal_i2c_bit_bang_priv_t; +static am_hal_i2c_bit_bang_priv_t am_hal_i2c_bit_bang_priv; + +// +// Wait for any stretched clock to go high +// If it times out - return failure +// +static inline bool +i2c_pull_and_wait_scl_hi(void) +{ + // Maximum time to wait for clock stretching + uint32_t maxLoop = 4*I2C_BB_MAX_CLOCK_STRETCH_WAIT + 1; + // Pull SCL High + PULL_SCL_HI(); + // Poll for SCL to check for clock stretching + while (!GET_SCL()) + { + if (--maxLoop == 0) + { + // timeout! + return true; + } + WAIT_FOR_QUARTER_I2C_CLOCK(); + } + return false; +} + +//***************************************************************************** +// +//! @brief Initialize i2c bit bang private data structure +//! +//! @param sck_gpio_number is the GPIO # for the I2C SCK clock pin +//! @param sda_gpio_number is the GPIO # for the I2C SDA data pin +//! +//! This function initializes the I2C bit bang utility's internal data struct. +//! +//! returns None. +// +//***************************************************************************** +am_hal_i2c_bit_bang_enum_t +am_hal_i2c_bit_bang_init(uint32_t sck_gpio_number, + uint32_t sda_gpio_number) +{ + int i; + // + // remember GPIO pin assignments for I2C bus signals + // + am_hal_i2c_bit_bang_priv.sck_gpio_number = sck_gpio_number; + am_hal_i2c_bit_bang_priv.sda_gpio_number = sda_gpio_number; + + am_hal_i2c_bit_bang_priv.sck_reg_set_addr = AM_HAL_GPIO_WTS_REG(sck_gpio_number); + am_hal_i2c_bit_bang_priv.sck_reg_clr_addr = AM_HAL_GPIO_WTC_REG(sck_gpio_number); + am_hal_i2c_bit_bang_priv.sck_reg_read_addr = AM_HAL_GPIO_RD_REG(sck_gpio_number); + am_hal_i2c_bit_bang_priv.sck_reg_val = AM_HAL_GPIO_WTC_M(sck_gpio_number); + am_hal_i2c_bit_bang_priv.sda_reg_set_addr = AM_HAL_GPIO_WTS_REG(sda_gpio_number); + am_hal_i2c_bit_bang_priv.sda_reg_clr_addr = AM_HAL_GPIO_WTC_REG(sda_gpio_number); + am_hal_i2c_bit_bang_priv.sda_reg_read_addr = AM_HAL_GPIO_RD_REG(sda_gpio_number); + am_hal_i2c_bit_bang_priv.sda_reg_val = AM_HAL_GPIO_WTC_M(sda_gpio_number); + + // + // Set SCK GPIO data bit high so we aren't pulling down the clock + // + am_hal_gpio_out_bit_set(sck_gpio_number); + // + // Set up SCK GPIO configuration bi-direction, input + // + am_hal_gpio_pin_config(sck_gpio_number, AM_HAL_PIN_OPENDRAIN); + + // + // Set SDA GPIO data bit high so we aren't pulling down the data line + // + am_hal_gpio_out_bit_set(sda_gpio_number); + // + // Set up SDA GPIO configuration bi-direction, input + // + am_hal_gpio_pin_config(sda_gpio_number, AM_HAL_PIN_OPENDRAIN); + + // Now make sure we have control of the clock line + // + // Wait for any stretched clock to go high. Return if still not high + // + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + if (!GET_SDA()) + { + // If previous transaction did not finish - SDA may be pulled low for a Read. + // If so - need to flush out the data (max 8 bits) & NACK + for (i = 0; i < 9; i++) + { + // + // Pull down on clock line + // + WRITE_SCL_LO(); + // + // Delay for 1/2 bit cell time to start the clock and let peer write on SDA + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + if (GET_SDA()) + { + // Send START/STOP to clear the bus + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + WRITE_SDA_LO(); + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + // + // Pull down on clock line + // + WRITE_SCL_LO(); + // + // Delay for 1/2 bit cell time to start the clock and let peer write on SDA + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + // + // Release the clock line + // + PULL_SCL_HI(); + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + PULL_SDA_HI(); + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + break; + } + } + if (i == 9) + { + // It is it still stuck after 9 clocks - something is wrong. Need to bail out + return AM_HAL_I2C_BIT_BANG_DATA_TIMEOUT; + } + } + return AM_HAL_I2C_BIT_BANG_SUCCESS; +} + +//***************************************************************************** +// +//! @brief Receive one data byte from an I2C device +//! +//! This function handles sending one byte to a slave device +//! bNack defines if we should send an ACK or NACK +//! +//! returns the byte received +// +//***************************************************************************** +static inline am_hal_i2c_bit_bang_enum_t +i2c_receive_byte(uint8_t *pRxByte, bool bNack) +{ + int i; + uint8_t data_byte = 0; + + // + // Loop through receiving 8 bits + // + for (i = 0; i < 8; i++) + { + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // release the data line from from the previous ACK + // + PULL_SDA_HI(); + + // + // Delay for 1/2 bit cell time to start the clock and let peer write on SDA + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // grab the data bit here + // + if ( GET_SDA() ) + { + // + // set the bit in the data byte to be returned + // + data_byte |= (0x80 >> i); + } + + // + // Delay for 1/2 bit cell time while clock is high + // + WAIT_I2C_CLOCK_HI_PERIOD(); + } + + *pRxByte = data_byte; + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // pull the data line down so we can ACK/NAK the byte we just received + // + if (bNack) + { + // + // Pull up on data line with clock low to indicate NAK + // + PULL_SDA_HI(); + } + else + { + // + // Pull down on data line with clock low to indicate ACK + // + WRITE_SDA_LO(); + } + // + // Delay for 1/2 bit cell time before sending ACK to device + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Delay for 1/2 bit cell time while clock is high to le peer sample the ACK/NAK + // + WAIT_I2C_CLOCK_HI_PERIOD(); + // + // Give the received data byte back to them + // + return AM_HAL_I2C_BIT_BANG_SUCCESS; +} + +//***************************************************************************** +// +//! @brief Send one data bytes to an I2C device +//! +//! @param one_byte the byte to send, could be address could be data +//! +//! This function handles sending one byte to a slave device +//! Starts with 0 clock and runs till full cycle +//! +//! returns I2C BB ENUM +//! { +//! AM_HAL_I2C_BIT_BANG_SUCCESS, +//! AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED +//! } +// +//***************************************************************************** +static inline am_hal_i2c_bit_bang_enum_t +i2c_send_byte(uint8_t one_byte) +{ + int i; + bool data_naked = false; + + // + // Loop through sending 8 bits + // + for (i = 0; i < 8; i++) + { + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // output the next data bit + // + if ( one_byte & (0x80 >> i) ) + { + PULL_SDA_HI(); + } + else + { + WRITE_SDA_LO(); + } + + // + // Delay for 1/2 bit cell time to start the clock + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Delay for 1/2 bit cell time while clock is high + // + WAIT_I2C_CLOCK_HI_PERIOD(); + } + + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // Delay for 1/2 bit cell time to start the clock + // + WAIT_I2C_CLOCK_LOW_PERIOD(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Grab the state of the ACK bit and return it + // + data_naked = GET_SDA(); + // + // Delay for 1/2 bit cell time to complete the high period + // + WAIT_I2C_CLOCK_HI_PERIOD(); + if ( data_naked ) + { + return AM_HAL_I2C_BIT_BANG_DATA_NAKED; + } + else + { + return AM_HAL_I2C_BIT_BANG_SUCCESS; + } +} + +//***************************************************************************** +// +//! @brief Receive a string of data bytes from an I2C device +//! +//! @param address (only 8 bit I2C addresses are supported) +//! LSB is I2C R/W +//! @param number_of_bytes to transfer (# payload bytes) +//! @param pData pointer to data buffer to receive payload +//! +//! This function handles receiving a payload from a slave device +//! +//! returns ENUM{AM_HAL_I2C_BIT_BANG_SUCCESS,AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED} +// +//***************************************************************************** +am_hal_i2c_bit_bang_enum_t +am_hal_i2c_bit_bang_receive(uint8_t address, uint32_t number_of_bytes, + uint8_t *pData, uint8_t ui8Offset, + bool bUseOffset, bool bNoStop) +{ + uint32_t ui32I; + am_hal_i2c_bit_bang_enum_t status = AM_HAL_I2C_BIT_BANG_SUCCESS; + + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Pull down on data line with clock high --> START CONDITION + // + WRITE_SDA_LO(); + + // + // Delay for 1/2 bit cell time to start the clock + // + WAIT_I2C_CLOCK_HI_PERIOD(); + + // + // send the address byte and wait for the ACK/NAK + // + status = i2c_send_byte(address); + if ( status != AM_HAL_I2C_BIT_BANG_SUCCESS ) + { + if ( status == AM_HAL_I2C_BIT_BANG_DATA_NAKED) + { + return AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED; + } + return status; + } + + if ( bUseOffset ) + { + status = i2c_send_byte(ui8Offset); + if ( status != AM_HAL_I2C_BIT_BANG_SUCCESS ) + { + return status; + } + } + + // + // receive the requested number of data bytes + // + for (ui32I = 0; ui32I < number_of_bytes - 1; ui32I++) + { + // + // receive the data bytes and send ACK for each one + // + status = i2c_receive_byte(pData, false); + if (status != AM_HAL_I2C_BIT_BANG_SUCCESS) + { + return status; + } + pData++; + } + // Send NAK for the last byte + status = i2c_receive_byte(pData, true); + if (status != AM_HAL_I2C_BIT_BANG_SUCCESS) + { + return status; + } + + //******************** + // Send stop condition + //******************** + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + + + if (!bNoStop) + { + // + // Pull down on data line with clock low + // + WRITE_SDA_LO(); + } + else + { + // + // Release data line with clock low itself, as we are not sending STOP + // + PULL_SDA_HI(); + } + // + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Delay for 1/2 bit cell time while clock is high + // + WAIT_I2C_CLOCK_HI_PERIOD(); + + if (!bNoStop) + { + // + // release data line with clock high --> STOP CONDITION + // + PULL_SDA_HI(); + } + + // + // message successfully received (how could we fail???) + // + return AM_HAL_I2C_BIT_BANG_SUCCESS; +} + +//***************************************************************************** +// +//! @brief Send a string of data bytes to an I2C device +//! +//! @param address (only 8 bit I2C addresses are supported) +//! LSB is I2C R/W +//! @param number_of_bytes to transfer (# payload bytes) +//! @param pData pointer to data buffer containing payload +//! +//! This function handles sending a payload to a slave device +//! +//! returns ENUM {AM_HAL_I2C_BIT_BANG_SUCCESS, AM_HAL_I2C_BIT_BANG_DATA_NAKED, +//! AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED} +// +//***************************************************************************** +am_hal_i2c_bit_bang_enum_t +am_hal_i2c_bit_bang_send(uint8_t address, uint32_t number_of_bytes, + uint8_t *pData, uint8_t ui8Offset, + bool bUseOffset, bool bNoStop) +{ + uint32_t ui32I; + am_hal_i2c_bit_bang_enum_t status; + bool data_naked = false; + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + // + // Pull down on data line with clock high --> START CONDITION + // + WRITE_SDA_LO(); + + // + // Delay for 1/2 bit cell time to start the clock + // + WAIT_I2C_CLOCK_HI_PERIOD(); + + // + // send the address byte and wait for the ACK/NAK + // + status = i2c_send_byte(address); + if ( status != AM_HAL_I2C_BIT_BANG_SUCCESS ) + { + if ( status == AM_HAL_I2C_BIT_BANG_DATA_NAKED) + { + return AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED; + } + return status; + } + + if ( bUseOffset ) + { + status = i2c_send_byte(ui8Offset); + if ( status != AM_HAL_I2C_BIT_BANG_SUCCESS ) + { + return status; + } + } + + // + // send the requested number of data bytes + // + for (ui32I = 0; ui32I < number_of_bytes; ui32I++) + { + // + // send out the data bytes while watching for premature NAK + // + status = i2c_send_byte(*pData++); + if (status != AM_HAL_I2C_BIT_BANG_SUCCESS) + { + if (status == AM_HAL_I2C_BIT_BANG_DATA_NAKED) + { + if (ui32I != (number_of_bytes-1)) + { + data_naked = true; + // TODO - should we be sending the STOP bit in this case regardless of bNoStop? + break; + } + else + { + status = AM_HAL_I2C_BIT_BANG_SUCCESS; + } + } + else + { + return status; + } + } + } + + //******************** + // Send stop condition + //******************** + + // + // Pull down on clock line + // + WRITE_SCL_LO(); + + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + + + if (!bNoStop) + { + // + // Pull down on data line with clock low + // + WRITE_SDA_LO(); + } + else + { + // + // Release data line with clock low itself, as we are not sending STOP + // + PULL_SDA_HI(); + } + + // + // Delay for 1/4 bit cell time + // + WAIT_FOR_QUARTER_I2C_CLOCK(); + + if (i2c_pull_and_wait_scl_hi()) + { + return AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT; + } + if (!bNoStop) + { + // + // release data line with clock high --> STOP CONDITION + // + PULL_SDA_HI(); + } + + // + // Delay for 1/2 bit cell time while clock is high + // + WAIT_I2C_CLOCK_HI_PERIOD(); + + if ( data_naked ) + { + return AM_HAL_I2C_BIT_BANG_DATA_NAKED; // if it happens early + } + + // + // message successfully sent + // + return AM_HAL_I2C_BIT_BANG_SUCCESS; +} diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.h b/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.h new file mode 100644 index 0000000000..a9571edbe5 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_i2c_bit_bang.h @@ -0,0 +1,100 @@ +//***************************************************************************** +// +// am_hal_i2c_bit_bang.h +//! @file +//! +//! @brief I2C bit bang module. +//! +//! These functions implement the I2C bit bang utility +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_I2C_BIT_BANG_H +#define AM_HAL_I2C_BIT_BANG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Enumerated return constants +// +//***************************************************************************** +typedef enum +{ + AM_HAL_I2C_BIT_BANG_SUCCESS = 0, + AM_HAL_I2C_BIT_BANG_ADDRESS_NAKED, + AM_HAL_I2C_BIT_BANG_DATA_NAKED, + AM_HAL_I2C_BIT_BANG_CLOCK_TIMEOUT, + AM_HAL_I2C_BIT_BANG_DATA_TIMEOUT, +}am_hal_i2c_bit_bang_enum_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern am_hal_i2c_bit_bang_enum_t am_hal_i2c_bit_bang_init(uint32_t sck_gpio_number, + uint32_t sda_gpio_number); + +extern am_hal_i2c_bit_bang_enum_t am_hal_i2c_bit_bang_send(uint8_t address, + uint32_t number_of_bytes, + uint8_t *pData, + uint8_t ui8Offset, + bool bUseOffset, + bool bNoStop); + +extern am_hal_i2c_bit_bang_enum_t am_hal_i2c_bit_bang_receive(uint8_t address, + uint32_t number_of_bytes, + uint8_t *pData, + uint8_t ui8Offset, + bool bUseOffset, + bool bNoStop); +#ifdef __cplusplus +} +#endif + +#endif //AM_HAL_I2C_BIT_BANG_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.c b/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.c new file mode 100644 index 0000000000..2f93b09cfc --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.c @@ -0,0 +1,407 @@ +//***************************************************************************** +// +// am_hal_interrupt.c +//! @file +//! +//! @brief Helper functions supporting interrupts and NVIC operation. +//! +//! These functions may be used for NVIC-level interrupt configuration. +//! +//! @addtogroup interrupt2 Interrupt (ARM NVIC support functions) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Enable an interrupt. +//! +//! @param ui32Interrupt The ISR number of the interrupt to be enabled. +//! +//! This function enables an interrupt signal to the NVIC based on the provided +//! ISR number. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_interrupt_enable(uint32_t ui32Interrupt) +{ + // + // Check to see what type of interrupt this is. + // + if ( ui32Interrupt > 15 ) + { + // + // If this ISR number corresponds to a "normal" peripheral interrupt, + // enable it using the NVIC register. + // + AM_REG(NVIC, ISER0) = 0x1 << ((ui32Interrupt - 16) & 0x1F); + } + else + { + // + // If this is an ARM internal interrupt number, route it to the + // appropriate enable register. + // + switch(ui32Interrupt) + { + case AM_HAL_INTERRUPT_BUSFAULT: + AM_BFW(SYSCTRL, SHCSR, BUSFAULTENA, 1); + break; + + case AM_HAL_INTERRUPT_USAGEFAULT: + AM_BFW(SYSCTRL, SHCSR, USAGEFAULTENA, 1); + break; + + case AM_HAL_INTERRUPT_MPUFAULT: + AM_BFW(SYSCTRL, SHCSR, MEMFAULTENA, 1); + break; + } + } +} + +//***************************************************************************** +// +//! @brief Disable an interrupt. +//! +//! @param ui32Interrupt The ISR number of the interrupt to be disabled. +//! +//! This function disables an interrupt signal to the NVIC based on the +//! provided ISR number. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_interrupt_disable(uint32_t ui32Interrupt) +{ + // + // Check to see what type of interrupt this is. + // + if ( ui32Interrupt > 15 ) + { + // + // If this ISR number corresponds to a "normal" peripheral interrupt, + // disable it using the NVIC register. + // + AM_REG(NVIC, ICER0) = 0x1 << ((ui32Interrupt - 16) & 0x1F); + } + else + { + // + // If this is an ARM internal interrupt number, route it to the + // appropriate enable register. + // + switch(ui32Interrupt) + { + case AM_HAL_INTERRUPT_BUSFAULT: + AM_BFW(SYSCTRL, SHCSR, BUSFAULTENA, 0); + break; + + case AM_HAL_INTERRUPT_USAGEFAULT: + AM_BFW(SYSCTRL, SHCSR, USAGEFAULTENA, 0); + break; + + case AM_HAL_INTERRUPT_MPUFAULT: + AM_BFW(SYSCTRL, SHCSR, MEMFAULTENA, 0); + break; + } + } +} + +//***************************************************************************** +// +//! @brief Set the priority of an interrupt vector. +//! +//! @param ui32Interrupt is the ISR number of the interrupt to change. +//! @param ui32Priority is the new ISR priority value. +//! +//! This function changes the priority value in the NVIC for the given +//! interrupt vector number. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_interrupt_priority_set(uint32_t ui32Interrupt, uint32_t ui32Priority) +{ + volatile uint32_t *pui32PriorityReg; + volatile uint32_t ui32OldPriority; + uint32_t ui32Shift; + + // + // Find the correct priority register. + // + pui32PriorityReg = (volatile uint32_t *) AM_REG_NVIC_IPR0_O; + pui32PriorityReg += ((ui32Interrupt - 16) >> 2); + + // + // Find the correct shift value. + // + ui32Shift = (((ui32Interrupt - 16) & 0x3) * 8); + + // + // Mask out the old priority. + // + ui32OldPriority = *pui32PriorityReg; + ui32OldPriority &= ~(0xFF << ui32Shift); + + // + // OR in the new priority. + // + *pui32PriorityReg |= (ui32Priority << ui32Shift); +} + +//***************************************************************************** +// +//! @brief Set a pending interrupt bit in the NVIC (Software Interrupt) +//! +//! @param ui32Interrupt is the ISR number of the interrupt to change. +//! +//! This function sets the specified bit in the Interrupt Set Pending (ISPR0) +//! register. For future MCUs there may be more than one ISPR. +//! +//! @return None +// +//***************************************************************************** +void am_hal_interrupt_pend_set(uint32_t ui32Interrupt) +{ + // + // Check to see if the specified interrupt is valid for this MCU + // + if ( ui32Interrupt > 47 ) + { + return; + } + + // + // Check to see what type of interrupt this is. + // + if ( ui32Interrupt > 15 ) + { + // + // If this ISR number corresponds to a "normal" peripheral interrupt, + // disable it using the NVIC register. + // + AM_REG(NVIC, ISPR0) = 0x1 << ((ui32Interrupt - 16) & 0x1F); + } +} + +//***************************************************************************** +// +//! @brief Clear a pending interrupt bit in the NVIC without servicing it +//! +//! @param ui32Interrupt is the ISR number of the interrupt to change. +//! +//! This function clears the specified bit in the Interrupt Clear Pending +//! (ICPR0) register. For future MCUs there may be more than one ICPR. This +//! function is useful immediately following a WFI before interrupts are +//! re-enabled. +//! +//! @return None +// +//***************************************************************************** +void am_hal_interrupt_pend_clear(uint32_t ui32Interrupt) +{ + // + // Check to see if the specified interrupt is valid for this MCU + // + if ( ui32Interrupt > 47 ) + { + return; + } + + // + // Check to see what type of interrupt this is. + // + if ( ui32Interrupt > 15 ) + { + // + // If this ISR number corresponds to a "normal" peripheral interrupt, + // disable it using the NVIC register. + // + AM_REG(NVIC, ICPR0) = 0x1 << ((ui32Interrupt - 16) & 0x1F); + } +} + +//***************************************************************************** +// +//! @brief Globally enable interrupt service routines +//! +//! This function allows interrupt signals from the NVIC to trigger ISR entry +//! in the CPU. This function must be called if interrupts are to be serviced +//! in software. +//! +//! @return 1 if interrupts were previously disabled, 0 otherwise. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +uint32_t __attribute__((naked)) +am_hal_interrupt_master_enable(void) +{ + __asm(" mrs r0, PRIMASK"); + __asm(" cpsie i"); + __asm(" bx lr"); +} +#elif defined(__ARMCC_VERSION) +__asm uint32_t +am_hal_interrupt_master_enable(void) +{ + mrs r0, PRIMASK + cpsie i + bx lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing + // return statement on a non-void function +__stackless uint32_t +am_hal_interrupt_master_enable(void) +{ + __asm(" mrs r0, PRIMASK"); + __asm(" cpsie i"); + __asm(" bx lr"); +} +#pragma diag_default = Pe940 // Restore IAR compiler warning +#endif + +//***************************************************************************** +// +//! @brief Globally disable interrupt service routines +//! +//! This function prevents interrupt signals from the NVIC from triggering ISR +//! entry in the CPU. This will effectively stop incoming interrupt sources +//! from triggering their corresponding ISRs. +//! +//! @note Any external interrupt signal that occurs while the master interrupt +//! disable is active will still reach the "pending" state in the NVIC, but it +//! will not be allowed to reach the "active" state or trigger the +//! corresponding ISR. Instead, these interrupts are essentially "queued" until +//! the next time the master interrupt enable instruction is executed. At that +//! time, the interrupt handlers will be executed in order of decreasing +//! priority. +//! +//! @return 1 if interrupts were previously disabled, 0 otherwise. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +uint32_t __attribute__((naked)) +am_hal_interrupt_master_disable(void) +{ + __asm(" mrs r0, PRIMASK"); + __asm(" cpsid i"); + __asm(" bx lr"); +} +#elif defined(__ARMCC_VERSION) +__asm uint32_t +am_hal_interrupt_master_disable(void) +{ + mrs r0, PRIMASK + cpsid i + bx lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing + // return statement on a non-void function +__stackless uint32_t +am_hal_interrupt_master_disable(void) +{ + __asm(" mrs r0, PRIMASK"); + __asm(" cpsid i"); + __asm(" bx lr"); +} +#pragma diag_default = Pe940 // Restore IAR compiler warning +#endif + +//***************************************************************************** +// +//! @brief Sets the master interrupt state based on the input. +//! +//! @param ui32InterruptState - Desired PRIMASK value. +//! +//! This function directly writes the PRIMASK register in the ARM core. A value +//! of 1 will disable interrupts, while a value of zero will enable them. +//! +//! This function may be used along with am_hal_interrupt_master_disable() to +//! implement a nesting critical section. To do this, call +//! am_hal_interrupt_master_disable() to start the critical section, and save +//! its return value. To complete the critical section, call +//! am_hal_interrupt_master_set() using the saved return value as \e +//! ui32InterruptState. This will safely restore PRIMASK to the value it +//! contained just before the start of the critical section. +//! +//! @return None. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +void __attribute__((naked)) +am_hal_interrupt_master_set(uint32_t ui32InterruptState) +{ + __asm(" msr PRIMASK, r0"); + __asm(" bx lr"); +} +#elif defined(__ARMCC_VERSION) +__asm void +am_hal_interrupt_master_set(uint32_t ui32InterruptState) +{ + msr PRIMASK, r0 + bx lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing + // return statement on a non-void function +__stackless void +am_hal_interrupt_master_set(uint32_t ui32InterruptState) +{ + __asm(" msr PRIMASK, r0"); + __asm(" bx lr"); +} +#pragma diag_default = Pe940 // Restore IAR compiler warning +#endif + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.h b/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.h new file mode 100644 index 0000000000..a8523371eb --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_interrupt.h @@ -0,0 +1,159 @@ +//***************************************************************************** +// +// am_hal_interrupt.h +//! @file +//! +//! @brief Helper functions supporting interrupts and NVIC operation. +//! +//! These functions may be used for NVIC-level interrupt configuration. +//! +//! @addtogroup interrupt2 Interrupt (ARM NVIC support functions) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_INTERRUPT_H +#define AM_HAL_INTERRUPT_H + +#ifdef __cplusplus +extern "C" +{ +#endif +//***************************************************************************** +// +//! @name ISR number macros. +//! @brief ISR macros. +//! +//! These macros are used for all ui32Interrupt arguments in this module. +//! @{ +// +//***************************************************************************** +// +// Hardware interrupts +// +#define AM_HAL_INTERRUPT_RESET 1 +#define AM_HAL_INTERRUPT_NMI 2 +#define AM_HAL_INTERRUPT_HARDFAULT 3 +#define AM_HAL_INTERRUPT_MPUFAULT 4 +#define AM_HAL_INTERRUPT_BUSFAULT 5 +#define AM_HAL_INTERRUPT_USAGEFAULT 6 + +#define AM_HAL_INTERRUPT_SVCALL 11 +#define AM_HAL_INTERRUPT_DEBUGMON 12 +#define AM_HAL_INTERRUPT_PENDSV 14 +#define AM_HAL_INTERRUPT_SYSTICK 15 + +// +// Begin IRQs +// +#define AM_HAL_INTERRUPT_BROWNOUT 16 +#define AM_HAL_INTERRUPT_WATCHDOG 17 +#define AM_HAL_INTERRUPT_CLKGEN 18 +#define AM_HAL_INTERRUPT_VCOMP 19 +#define AM_HAL_INTERRUPT_IOSLAVE 20 +#define AM_HAL_INTERRUPT_IOSACC 21 +#define AM_HAL_INTERRUPT_IOMASTER0 22 +#define AM_HAL_INTERRUPT_IOMASTER1 23 +#define AM_HAL_INTERRUPT_IOMASTER2 24 +#define AM_HAL_INTERRUPT_IOMASTER3 25 +#define AM_HAL_INTERRUPT_IOMASTER4 26 +#define AM_HAL_INTERRUPT_IOMASTER5 27 +#define AM_HAL_INTERRUPT_GPIO 28 +#define AM_HAL_INTERRUPT_CTIMER 29 +#define AM_HAL_INTERRUPT_UART0 30 +#define AM_HAL_INTERRUPT_UART1 31 +#define AM_HAL_INTERRUPT_UART (AM_HAL_INTERRUPT_UART0) +#define AM_HAL_INTERRUPT_ADC 32 +#define AM_HAL_INTERRUPT_PDM 33 +#define AM_HAL_INTERRUPT_STIMER 34 +#define AM_HAL_INTERRUPT_STIMER_CMPR0 35 +#define AM_HAL_INTERRUPT_STIMER_CMPR1 36 +#define AM_HAL_INTERRUPT_STIMER_CMPR2 37 +#define AM_HAL_INTERRUPT_STIMER_CMPR3 38 +#define AM_HAL_INTERRUPT_STIMER_CMPR4 39 +#define AM_HAL_INTERRUPT_STIMER_CMPR5 40 +#define AM_HAL_INTERRUPT_STIMER_CMPR6 41 +#define AM_HAL_INTERRUPT_STIMER_CMPR7 42 +#define AM_HAL_INTERRUPT_FLASH 43 + +#define AM_HAL_INTERRUPT_SOFTWARE0 44 +#define AM_HAL_INTERRUPT_SOFTWARE1 45 +#define AM_HAL_INTERRUPT_SOFTWARE2 46 +#define AM_HAL_INTERRUPT_SOFTWARE3 47 +//! @} + +//***************************************************************************** +// +//! @brief Interrupt priority +//! +//! This macro is made to be used with the \e am_hal_interrupt_priority_set() +//! function. It converts a priority number to the format used by the ARM +//! standard priority register, where only the top 3 bits are used. +//! +//! For example, AM_HAL_INTERRUPT_PRIORITY(1) yields a value of 0x20. +// +//***************************************************************************** +#define AM_HAL_INTERRUPT_PRIORITY(n) (((uint32_t)(n) & 0x7) << 5) + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_interrupt_enable(uint32_t ui32Interrupt); +extern void am_hal_interrupt_disable(uint32_t ui32Interrupt); +extern void am_hal_interrupt_pend_set(uint32_t ui32Interrupt); +extern void am_hal_interrupt_pend_clear(uint32_t ui32Interrupt); +extern void am_hal_interrupt_priority_set(uint32_t ui32Interrupt, + uint32_t ui32Priority); +extern uint32_t am_hal_interrupt_master_disable(void); +extern uint32_t am_hal_interrupt_master_enable(void); +extern void am_hal_interrupt_master_set(uint32_t ui32InterruptState); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_INTERRUPT_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_iom.c b/bsp/apollo2/libraries/drivers/hal/am_hal_iom.c new file mode 100644 index 0000000000..8b85c32b6a --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_iom.c @@ -0,0 +1,4426 @@ +//***************************************************************************** +// +// am_hal_iom.c +//! @file +//! +//! @brief Functions for interfacing with the IO Master module +//! +//! @addtogroup iom2 IO Master (SPI/I2C) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" +#include "am_util_delay.h" + +#ifdef __IAR_SYSTEMS_ICC__ +#define AM_INSTR_CLZ(n) __CLZ(n) +#else +#define AM_INSTR_CLZ(n) __builtin_clz(n) +#endif + +//! ASSERT(1) or Correct(0) invalid IOM R/W Thresholds. +#ifndef AM_ASSERT_INVALID_THRESHOLD +#define AM_ASSERT_INVALID_THRESHOLD (1) +#endif + +//***************************************************************************** +// +// Forcing optimizations +// +// These pragmas must be enabled if we intend to use the IOM4 workaround with a +// delay higher than 18-bits in the first word. +// +//***************************************************************************** +//#ifdef __IAR_SYSTEMS_ICC__ +//#pragma optimize=3 s +//#endif +// +//#ifdef __ARMCC_VERSION +//#pragma O3 +//#endif +// +//#ifdef __GNUC__ +//#pragma GCC optimize ("O3") +//#endif + +//***************************************************************************** +// +// Forward declarations. +// +//***************************************************************************** +static void iom_workaround_loop(uint32_t ui32PadRegVal, + volatile uint32_t *pui32PadReg, + bool bRising); +static uint32_t +internal_am_hal_iom_spi_cmd_construct(uint32_t ui32Operation, + uint32_t ui32ChipSelect, + uint32_t ui32NumBytes, + uint32_t ui32Options); + +//***************************************************************************** +// +// IOM Buffer states. +// +//***************************************************************************** +#define BUFFER_IDLE 0x0 +#define BUFFER_SENDING 0x1 +#define BUFFER_RECEIVING 0x2 + +//***************************************************************************** +// +// Global state variables +// +//***************************************************************************** +// +// Save error status from ISR, particularly for use in I2C queue mode. +// +uint32_t g_iom_error_status = 0; + +// +// Define a structure to map CE for IOM4 only. +// +typedef struct +{ + uint8_t channel; // CE channel for SPI + uint8_t pad; // GPIO Pad + uint8_t funcsel; // FNCSEL value +} IOMPad_t; + +// Define the mapping between SPI CEn, Pads, and FNCSEL values for all IOMs. +const IOMPad_t g_IOMPads[] = +{ + {0, 29, 6}, {0, 34, 6}, {1, 18, 4}, {1, 37, 5}, {2, 41, 6}, + {3, 17, 4}, {3, 45, 4}, {4, 10, 6}, {4, 46, 6}, {5, 9, 4}, + {5, 47, 6}, {6, 35, 4}, {7, 38, 6} +}; + +#define WORKAROUND_IOM 4 +#define WORKAROUND_IOM_MOSI_PIN 44 +#define WORKAROUND_IOM_MOSI_CFG AM_HAL_PIN_44_M4MOSI + +#define MAX_IOM_BITS 9 +#define IOM_OVERHEAD_FACTOR 2 + +//***************************************************************************** +// +// Non-blocking buffer and buffer-management variables. +// +//***************************************************************************** +typedef struct +{ + uint32_t ui32State; + uint32_t *pui32Data; + uint32_t ui32BytesLeft; + uint32_t ui32Options; + void (*pfnCallback)(void); +} +am_hal_iom_nb_buffer; + +// +// Global State to keep track if there is an ongoing transaction +// +volatile bool g_bIomBusy[AM_REG_IOMSTR_NUM_MODULES] = {0}; + +am_hal_iom_nb_buffer g_psIOMBuffers[AM_REG_IOMSTR_NUM_MODULES]; + +//***************************************************************************** +// +// Computed timeout. +// +// The IOM may not always respond to events (e.g., CMDCMP). This is a +// timeout value in cycles to be used when waiting on status changes. +//***************************************************************************** +uint32_t ui32StatusTimeout[AM_REG_IOMSTR_NUM_MODULES]; + +//***************************************************************************** +// +// Queue management variables. +// +//***************************************************************************** +am_hal_queue_t g_psIOMQueue[AM_REG_IOMSTR_NUM_MODULES]; + +//***************************************************************************** +// +// Default queue flush function +// +//***************************************************************************** +am_hal_iom_queue_flush_t am_hal_iom_queue_flush = am_hal_iom_sleeping_queue_flush; + +//***************************************************************************** +// +// Power management structure. +// +//***************************************************************************** +am_hal_iom_pwrsave_t am_hal_iom_pwrsave[AM_REG_IOMSTR_NUM_MODULES]; + + +//***************************************************************************** +// +// Static helper functions +// +//***************************************************************************** + +//***************************************************************************** +// onebit() +//***************************************************************************** +// +// A power of 2? +// Return true if ui32Value has exactly 1 bit set, otherwise false. +// +static bool onebit(uint32_t ui32Value) +{ + return ui32Value && !(ui32Value & (ui32Value - 1)); +} + +//***************************************************************************** +// compute_freq() +//***************************************************************************** +// +// Compute the interface frequency based on the given parameters +// +static uint32_t compute_freq(uint32_t ui32HFRCfreqHz, + uint32_t ui32Fsel, uint32_t ui32Div3, + uint32_t ui32DivEn, uint32_t ui32TotPer) +{ + uint32_t ui32Denomfinal, ui32ClkFreq; + + ui32Denomfinal = ((1 << (ui32Fsel - 1)) * (1 + ui32Div3 * 2) * (1 + ui32DivEn * (ui32TotPer))); + ui32ClkFreq = (ui32HFRCfreqHz) / ui32Denomfinal; // Compute the set frequency value + ui32ClkFreq += (((ui32HFRCfreqHz) % ui32Denomfinal) > (ui32Denomfinal / 2)) ? 1 : 0; + + return ui32ClkFreq; +} + +//***************************************************************************** +// iom_calc_gpio() +// +// Calculate the IOM4 GPIO to assert. +// +//***************************************************************************** +static uint32_t iom_calc_gpio(uint32_t ui32ChipSelect) +{ + uint32_t index; + uint8_t ui8PadRegVal, ui8FncSelVal; + + // + // Figure out which GPIO we are using for the IOM + // + for ( index = 0; index < (sizeof(g_IOMPads) / sizeof(IOMPad_t)); index++ ) + { + // + // Is this one of the CEn that we are using? + // + if ( g_IOMPads[index].channel == ui32ChipSelect ) + { + // + // Get the PAD register value + // + ui8PadRegVal = ((AM_REGVAL(AM_HAL_GPIO_PADREG(g_IOMPads[index].pad))) & + AM_HAL_GPIO_PADREG_M(g_IOMPads[index].pad)) >> + AM_HAL_GPIO_PADREG_S(g_IOMPads[index].pad); + + // + // Get the FNCSEL field value + // + ui8FncSelVal = (ui8PadRegVal & 0x38) >> 3; + + // + // Is the FNCSEL filed for this pad set to the expected value? + // + if ( ui8FncSelVal == g_IOMPads[index].funcsel ) + { + // This is the GPIO we need to use. + return g_IOMPads[index].pad; + } + } + } + return 0xDEADBEEF; +} + +//***************************************************************************** +// +// Checks to see if this processor is a Rev B0 device. +// +// This is needed for the B0 IOM workaround. +// +//***************************************************************************** +bool +isRevB0(void) +{ + // + // Check to make sure the major rev is B and the minor rev is zero. + // + if ( (AM_REG(MCUCTRL, CHIPREV) & 0xFF) == AM_REG_MCUCTRL_CHIPREV_REVMAJ_B ) + { + return true; + } + else + { + return false; + } +} + +//***************************************************************************** +// +//! @brief Returns the proper settings for the CLKCFG register. +//! +//! @param ui32FreqHz - The desired interface frequency in Hz. +//! ui32Phase - SPI phase (0 or 1). Can affect duty cycle. +//! +//! Given a desired serial interface clock frequency, this function computes +//! the appropriate settings for the various fields in the CLKCFG register +//! and returns the 32-bit value that should be written to that register. +//! The actual interface frequency may be slightly lower than the specified +//! frequency, but the actual frequency is also returned. +//! +//! @note A couple of criteria that this algorithm follow are: +//! 1. For power savings, choose the highest FSEL possible. +//! 2. For best duty cycle, use DIV3 when possible rather than DIVEN. +//! +//! An example of #1 is that both of the following CLKCFGs would result +//! in a frequency of 428,571 Hz: 0x0E071400 and 0x1C0E1300. +//! The former is chosen by the algorithm because it results in FSEL=4 +//! while the latter is FSEL=3. +//! +//! An example of #2 is that both of the following CLKCFGs would result +//! in a frequency of 2,000,000 Hz: 0x02011400 and 0x00000C00. +//! The latter is chosen by the algorithm because it results in use of DIV3 +//! rather than DIVEN. +//! +//! @return An unsigned 64-bit value. +//! The lower 32-bits represent the value to use to set CLKCFG. +//! The upper 32-bits represent the actual frequency (in Hz) that will result +//! from setting CLKCFG with the lower 32-bits. +//! +//! 0 (64 bits) = error. Note that the caller must check the entire 64 bits. +//! It is not an error if only the low 32-bits are 0 (this is a valid value). +//! But the entire 64 bits returning 0 is an error. +//! +//***************************************************************************** + +static +uint64_t iom_get_interface_clock_cfg(uint32_t ui32FreqHz, uint32_t ui32Phase ) +{ + uint32_t ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer, ui32LowPer; + uint32_t ui32Denom, ui32v1, ui32Denomfinal, ui32ClkFreq, ui32ClkCfg; + uint32_t ui32HFRCfreqHz; + int32_t i32Div, i32N; + + if ( ui32FreqHz == 0 ) + { + return 0; + } + + // + // Set the HFRC clock frequency. + // + ui32HFRCfreqHz = AM_HAL_CLKGEN_FREQ_MAX_HZ; + + // + // Compute various parameters used for computing the optimal CLKCFG setting. + // + i32Div = (ui32HFRCfreqHz / ui32FreqHz) + ((ui32HFRCfreqHz % ui32FreqHz) ? 1 : 0); // Round up (ceiling) + + // + // Compute N (count the number of LS zeros of Div) = ctz(Div) = log2(Div & (-Div)) + // + i32N = 31 - AM_INSTR_CLZ((i32Div & (-i32Div))); + + if ( i32N > 6 ) + { + i32N = 6; + } + + ui32Div3 = ( (ui32FreqHz < (ui32HFRCfreqHz / 16384)) || + ( ((ui32FreqHz >= (ui32HFRCfreqHz / 3)) && + (ui32FreqHz <= ((ui32HFRCfreqHz / 2) - 1)) ) ) ) ? 1 : 0; + ui32Denom = ( 1 << i32N ) * ( 1 + (ui32Div3 * 2) ); + ui32TotPer = i32Div / ui32Denom; + ui32TotPer += (i32Div % ui32Denom) ? 1 : 0; + ui32v1 = 31 - AM_INSTR_CLZ(ui32TotPer); // v1 = log2(TotPer) + ui32Fsel = (ui32v1 > 7) ? ui32v1 + i32N - 7 : i32N; + ui32Fsel++; + + if ( ui32Fsel > 7 ) + { + // + // This is an error, can't go that low. + // + return 0; + } + + if ( ui32v1 > 7 ) + { + ui32DivEn = ui32TotPer; // Save TotPer for the round up calculation + ui32TotPer = ui32TotPer>>(ui32v1-7); + ui32TotPer += ((ui32DivEn) % (1 << (ui32v1 - 7))) ? 1 : 0; + } + + ui32DivEn = ( (ui32FreqHz >= (ui32HFRCfreqHz / 4)) || + ((1 << (ui32Fsel - 1)) == i32Div) ) ? 0 : 1; + + if (ui32Phase == 1) + { + ui32LowPer = (ui32TotPer - 2) / 2; // Longer high phase + } + else + { + ui32LowPer = (ui32TotPer - 1) / 2; // Longer low phase + } + + ui32ClkCfg = AM_REG_IOMSTR_CLKCFG_FSEL(ui32Fsel) | + AM_REG_IOMSTR_CLKCFG_DIV3(ui32Div3) | + AM_REG_IOMSTR_CLKCFG_DIVEN(ui32DivEn) | + AM_REG_IOMSTR_CLKCFG_LOWPER(ui32LowPer) | + AM_REG_IOMSTR_CLKCFG_TOTPER(ui32TotPer - 1); + + + // + // Now, compute the actual frequency, which will be returned. + // + ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer - 1); + + // + // Determine if the actual frequency is a power of 2 (MHz). + // + if ( (ui32ClkFreq % 250000) == 0 ) + { + // + // If the actual clock frequency is a power of 2 ranging from 250KHz up, + // we can simplify the CLKCFG value using DIV3 (which also results in a + // better duty cycle). + // + ui32Denomfinal = ui32ClkFreq / (uint32_t)250000; + + if ( onebit(ui32Denomfinal) ) + { + // + // These configurations can be simplified by using DIV3. Configs + // using DIV3 have a 50% duty cycle, while those from DIVEN will + // have a 66/33 duty cycle. + // + ui32TotPer = ui32LowPer = ui32DivEn = 0; + ui32Div3 = 1; + + // + // Now, compute the return values. + // + ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer); + + ui32ClkCfg = AM_REG_IOMSTR_CLKCFG_FSEL(ui32Fsel) | + AM_REG_IOMSTR_CLKCFG_DIV3(1) | + AM_REG_IOMSTR_CLKCFG_DIVEN(0) | + AM_REG_IOMSTR_CLKCFG_LOWPER(0) | + AM_REG_IOMSTR_CLKCFG_TOTPER(0); + } + } + + return ( ((uint64_t)ui32ClkFreq) << 32) | (uint64_t)ui32ClkCfg; + +} //iom_get_interface_clock_cfg() + + +//***************************************************************************** +// +//! @brief Enable the IOM in the power control block. +//! +//! This function enables the desigated IOM module in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_pwrctrl_enable(uint32_t ui32Module) +{ + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to enable an IOM module that doesn't exist."); + + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_IOM0 << ui32Module); +} + +//***************************************************************************** +// +//! @brief Disable the IOM in the power control block. +//! +//! This function disables the desigated IOM module in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_pwrctrl_disable(uint32_t ui32Module) +{ + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to disable an IOM module that doesn't exist."); + + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_IOM0 << ui32Module); +} + +//***************************************************************************** +// +//! @brief Enables the IOM module +//! +//! @param ui32Module - The number of the IOM module to be enabled. +//! +//! This function enables the IOM module using the IFCEN bitfield in the +//! IOMSTR_CFG register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_enable(uint32_t ui32Module) +{ + if ( ui32Module < AM_REG_IOMSTR_NUM_MODULES ) + { + AM_REGn(IOMSTR, ui32Module, CFG) |= AM_REG_IOMSTR_CFG_IFCEN(1); + g_bIomBusy[ui32Module] = false; + } +} + +//***************************************************************************** +// +//! @brief Disables the IOM module. +//! +//! @param ui32Module - The number of the IOM module to be disabled. +//! +//! This function disables the IOM module using the IFCEN bitfield in the +//! IOMSTR_CFG register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_disable(uint32_t ui32Module) +{ + if ( ui32Module < AM_REG_IOMSTR_NUM_MODULES ) + { + // + // Wait until the bus is idle. + // + am_hal_iom_poll_complete(ui32Module); + + // + // Disable the interface. + // + AM_REGn(IOMSTR, ui32Module, CFG) &= ~(AM_REG_IOMSTR_CFG_IFCEN(1)); + } +} + +//***************************************************************************** +// +//! @brief Enable power to the selected IOM module. +//! +//! @param ui32Module - Module number for the IOM to be turned on. +//! +//! This function enables the power gate to the selected IOM module. It is +//! intended to be used along with am_hal_iom_power_off_save(). Used together, +//! these functions allow the caller to power IOM modules off to save +//! additional power without losing important configuration information. +//! +//! The am_hal_iom_power_off_save() function will save IOM configuration +//! register information to SRAM before powering off the selected IOM module. +//! This function will re-enable the IOM module, and restore those +//! configuration settings from SRAM. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_power_on_restore(uint32_t ui32Module) +{ + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to enable an IOM module that doesn't exist."); + + // + // Make sure this restore is a companion to a previous save call. + // + if ( am_hal_iom_pwrsave[ui32Module].bValid == 0 ) + { + return; + } + + // + // Enable power to the selected IOM. + // + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_IOM0 << ui32Module); + + // + // Restore the IOM configuration registers from the structure in SRAM. + // + AM_REGn(IOMSTR, ui32Module, FIFOTHR) = am_hal_iom_pwrsave[ui32Module].FIFOTHR; + AM_REGn(IOMSTR, ui32Module, CLKCFG) = am_hal_iom_pwrsave[ui32Module].CLKCFG; + AM_REGn(IOMSTR, ui32Module, CFG) = am_hal_iom_pwrsave[ui32Module].CFG; + AM_REGn(IOMSTR, ui32Module, INTEN) = am_hal_iom_pwrsave[ui32Module].INTEN; + + // + // Indicates we have restored the configuration. + // + am_hal_iom_pwrsave[ui32Module].bValid = 0; +} + +//***************************************************************************** +// +//! @brief Disable power to the selected IOM module. +//! +//! @param ui32Module - Module number for the IOM to be turned off. +//! +//! This function disables the power gate to the selected IOM module. It is +//! intended to be used along with am_hal_iom_power_on_restore(). Used together, +//! these functions allow the caller to power IOM modules off to save +//! additional power without losing important configuration information. +//! +//! The am_hal_iom_power_off_save() function will save IOM configuration +//! register information to SRAM before powering off the selected IOM module. +//! The am_hal_iom_power_on_restore() function will re-enable the IOM module +//! and restore those configuration settings from SRAM. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_power_off_save(uint32_t ui32Module) +{ + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to disable an IOM module that doesn't exist."); + + // + // Save the IOM configuration registers to the structure in SRAM. + // + am_hal_iom_pwrsave[ui32Module].FIFOTHR = AM_REGn(IOMSTR, ui32Module, FIFOTHR); + am_hal_iom_pwrsave[ui32Module].CLKCFG = AM_REGn(IOMSTR, ui32Module, CLKCFG); + am_hal_iom_pwrsave[ui32Module].CFG = AM_REGn(IOMSTR, ui32Module, CFG); + am_hal_iom_pwrsave[ui32Module].INTEN = AM_REGn(IOMSTR, ui32Module, INTEN); + + // + // Indicates we have a valid saved configuration. + // + am_hal_iom_pwrsave[ui32Module].bValid = 1; + + // + // Disable power to the selected IOM. + // + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_IOM0 << ui32Module); +} + +// +//! Check and correct the IOM FIFO threshold. +// +#define MAX_RW_THRESHOLD (AM_HAL_IOM_MAX_FIFO_SIZE - 4) +#define MIN_RW_THRESHOLD (4) +#if (AM_ASSERT_INVALID_THRESHOLD == 0) +static uint8_t check_iom_threshold(const uint8_t iom_threshold) +{ + uint8_t corrected_threshold = iom_threshold; + + if ( corrected_threshold < MIN_RW_THRESHOLD ) + { + corrected_threshold = MIN_RW_THRESHOLD; + } + + if ( corrected_threshold > MAX_RW_THRESHOLD ) + { + corrected_threshold = MAX_RW_THRESHOLD; + } + + return corrected_threshold; +} +#endif + +//***************************************************************************** +// +//! @brief Sets module-wide configuration options for the IOM module. +//! +//! @param ui32Module - The instance number for the module to be configured +//! (zero or one) +//! +//! @param psConfig - Pointer to an IOM configuration structure. +//! +//! This function is used to set the interface mode (SPI or I2C), clock +//! frequency, SPI format (when relevant), and FIFO read/write interrupt +//! thresholds for the IO master. For more information on specific +//! configuration options, please see the documentation for the configuration +//! structure. +//! +//! @note The IOM module should be disabled before configuring or +//! re-configuring. This function will not re-enable the module when it +//! completes. Call the am_hal_iom_enable function when the module is +//! configured and ready to use. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_config(uint32_t ui32Module, const am_hal_iom_config_t *psConfig) +{ + uint32_t ui32Config, ui32ClkCfg; + + // + // Start by checking the interface mode (I2C or SPI), and writing it to the + // configuration word. + // + ui32Config = psConfig->ui32InterfaceMode; + + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Check the SPI format, and OR in the bits for SPHA (clock phase) and SPOL + // (polarity). These shouldn't have any effect in I2C mode, so it should be + // ok to write them without checking exactly which mode we're in. + // + if ( psConfig->bSPHA ) + { + ui32Config |= AM_REG_IOMSTR_CFG_SPHA(1); + } + + if ( psConfig->bSPOL ) + { + ui32Config |= AM_REG_IOMSTR_CFG_SPOL(1); + } + + // Set the STARTRD based on the interface speed + // For all I2C frequencies and SPI frequencies below 16 MHz, the STARTRD + // field should be set to 0 to minimize the potential of the IO transfer + // holding off a bus access to the FIFO. For SPI frequencies of 16 MHz + // or 24 MHz, the STARTRD field must be set to a value of 2 to insure + // enough time for the IO preread. + if ( psConfig->ui32ClockFrequency >= 16000000UL) + { + ui32Config |= AM_REG_IOMSTR_CFG_STARTRD(2); + } + + // + // Write the resulting configuration word to the IO master CFG register for + // the module number we were provided. + // + AM_REGn(IOMSTR, ui32Module, CFG) = ui32Config; + + // + // Write the FIFO write and read thresholds to the appropriate registers. + // +#if (AM_ASSERT_INVALID_THRESHOLD == 1) + am_hal_debug_assert_msg( + (psConfig->ui8WriteThreshold <= MAX_RW_THRESHOLD), "IOM write threshold too big."); + am_hal_debug_assert_msg( + (psConfig->ui8ReadThreshold <= MAX_RW_THRESHOLD), "IOM read threshold too big."); + am_hal_debug_assert_msg( + (psConfig->ui8WriteThreshold >= MIN_RW_THRESHOLD), "IOM write threshold too small."); + am_hal_debug_assert_msg( + (psConfig->ui8ReadThreshold >= MIN_RW_THRESHOLD), "IOM read threshold too small."); + + AM_REGn(IOMSTR, ui32Module, FIFOTHR) = + (AM_REG_IOMSTR_FIFOTHR_FIFOWTHR(psConfig->ui8WriteThreshold) | + AM_REG_IOMSTR_FIFOTHR_FIFORTHR(psConfig->ui8ReadThreshold)); +#elif (AM_ASSERT_INVALID_THRESHOLD == 0) + AM_REGn(IOMSTR, ui32Module, FIFOTHR) = + (AM_REG_IOMSTR_FIFOTHR_FIFOWTHR(check_iom_threshold(psConfig->ui8WriteThreshold)) | + AM_REG_IOMSTR_FIFOTHR_FIFORTHR(check_iom_threshold(psConfig->ui8ReadThreshold))); +#else +#error AM_ASSERT_INVALID_THRESHOLD must be 0 or 1. +#endif + + // + // An exception occurs in the LOWPER computation when setting an interface + // frequency (such as a divide by 5 frequency) which results in a 60/40 + // duty cycle. The 60% cycle must occur in the appropriate half-period, + // as only one of the half-periods is active, depending on which phase + // is being selected. + // If SPHA=0 the low period must be 60%. If SPHA=1 high period must be 60%. + // Note that the predetermined frequency parameters use the formula + // lowper = (totper-1)/2, which results in a 60% low period. + // + ui32ClkCfg = iom_get_interface_clock_cfg(psConfig->ui32ClockFrequency, + psConfig->bSPHA ); + if ( ui32ClkCfg ) + { + AM_REGn(IOMSTR, ui32Module, CLKCFG) = (uint32_t)ui32ClkCfg; + } + + // + // Compute the status timeout value. + // + ui32StatusTimeout[ui32Module] = MAX_IOM_BITS * AM_HAL_IOM_MAX_FIFO_SIZE * + IOM_OVERHEAD_FACTOR * (am_hal_clkgen_sysclk_get() / psConfig->ui32ClockFrequency); +} + +//***************************************************************************** +// +//! @brief Returns the actual currently configured interface frequency in Hz. +// +//***************************************************************************** +uint32_t +am_hal_iom_frequency_get(uint32_t ui32ClkCfg) +{ + uint32_t ui32Freq; + + ui32Freq = compute_freq(AM_HAL_CLKGEN_FREQ_MAX_HZ, + (ui32ClkCfg & AM_REG_IOMSTR_CLKCFG_FSEL_M) >> AM_REG_IOMSTR_CLKCFG_FSEL_S, + (ui32ClkCfg & AM_REG_IOMSTR_CLKCFG_DIV3_M) >> AM_REG_IOMSTR_CLKCFG_DIV3_S, + (ui32ClkCfg & AM_REG_IOMSTR_CLKCFG_DIVEN_M) >> AM_REG_IOMSTR_CLKCFG_DIVEN_S, + (ui32ClkCfg & AM_REG_IOMSTR_CLKCFG_TOTPER_M)>> AM_REG_IOMSTR_CLKCFG_TOTPER_S); + + return ui32Freq; +} + +//***************************************************************************** +// +// Helper function for the B0 workaround. +// +//***************************************************************************** +static uint32_t +iom_get_workaround_fsel(uint32_t maxFreq) +{ + uint32_t ui32Freq, ui32Fsel; + uint32_t ui32ClkCfg = AM_REGn(IOMSTR, 4, CLKCFG); + + // + // Starting with the current clock configuration parameters, find a value + // of FSEL that will bring our total frequency down to or below maxFreq. + // + for ( ui32Fsel = 1; ui32Fsel < 8; ui32Fsel++ ) + { + ui32Freq = compute_freq(AM_HAL_CLKGEN_FREQ_MAX_HZ, ui32Fsel, + AM_BFX(IOMSTR, CLKCFG, DIV3, ui32ClkCfg), + AM_BFX(IOMSTR, CLKCFG, DIVEN, ui32ClkCfg), + AM_BFX(IOMSTR, CLKCFG, TOTPER, ui32ClkCfg)); + + if ( ui32Freq <= maxFreq && ui32Freq != 0 ) + { + // + // Return the new FSEL + // + return ui32Fsel; + } + } + + // + // Couldn't find an appropriate frequency. This should be impossible + // because there should always be a value of FSEL that brings the final IOM + // frequency below 500 KHz. + // + am_hal_debug_assert_msg(false, "Could find a valid frequency. Should never get here."); + return maxFreq; +} + +// Separating this piece of code in separate function to keep the impact of +// rest of the code to mimimal because of stack usage +static void +internal_iom_workaround_critical(uint32_t ui32Command, + volatile uint32_t *pui32CSPadreg, + uint32_t ui32CSPadregVal, + uint32_t ui32DelayTime, + uint32_t ui32ClkCfg, + uint32_t ui32LowClkCfg, + bool bRising) +{ + uint32_t ui32Critical = 0; + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Start the write on the bus. + // + AM_REGn(IOMSTR, WORKAROUND_IOM, CMD) = ui32Command; + + // + // Slow down the clock, and run the workaround loop. The workaround + // loop runs an edge-detector on MOSI, and triggers a falling edge on + // chip-enable on the first bit of our real data. + // + ((void (*)(uint32_t)) 0x0800009d)(ui32DelayTime); + // Switch to Low Freq + AM_REGn(IOMSTR, WORKAROUND_IOM, CLKCFG) = ui32LowClkCfg; + iom_workaround_loop(ui32CSPadregVal, pui32CSPadreg, bRising); + // + // Restore the clock frequency and the normal MOSI pin function. + // + AM_REGn(IOMSTR, WORKAROUND_IOM, CLKCFG) = ui32ClkCfg; + am_hal_gpio_pin_config(WORKAROUND_IOM_MOSI_PIN, WORKAROUND_IOM_MOSI_CFG); + + // + // End the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + + +//***************************************************************************** +// +//! @brief Workaround for an Apollo2 Rev B0 issue. +//! +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional SPI transfer options. +//! +//! Some Apollo2 Rev B0 devices have an issue where the first byte of a SPI +//! write transaction can have some of its bits changed from ones to zeroes. In +//! order to get around this issue, we artificially pad the SPI write data with +//! additional bytes, and manually control the CS pin for the beginning of the +//! SPI frame so that the receiving device will ignore the bytes of padding +//! that we added. +//! +//! This function acts as a helper function to higher-level spi APIs. It +//! performs the functions of am_hal_iom_fifo_write() and +//! am_hal_iom_spi_cmd_run() to get a SPI write started on the bus, including +//! all of the necessary workaround behavior. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_workaround_word_write(uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32TransferSize; + uint32_t ui32IOMGPIO = 0xDEADBEEF; + volatile uint32_t *pui32CSPadreg = 0; + uint32_t ui32CSPadregVal = 0; + uint32_t ui32ClkCfg = 0; + uint32_t ui32HiClkCfg, ui32LowClkCfg; + bool bRising = 0; + uint32_t ui32HiFreq = 0, ui32NormalFreq = 0; + uint32_t ui32DelayTime = 0; + uint32_t ui32LowFsel = 0; + uint32_t ui32HiFsel = 0; + uint32_t ui32FirstWord = 0; + uint32_t ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, WORKAROUND_IOM, CFG, FULLDUP)) ? + AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + uint32_t ui32Command; + // + // Make sure the transfer isn't too long for the hardware to support. + // + // Note: This is a little shorter than usual, since the workaround + // consumes an extra byte at the beginning of the transfer. + // + am_hal_debug_assert_msg(ui32NumBytes <= 4091, "SPI transfer too big."); + + // + // Create a "dummy" word to add on to the beginning of the transfer + // that will guarantee a transition between the first word and the + // second on the bus. + // + // For raw transactions, this is straightforward. For transactions + // preceded by an offset, we'll add the offset in to the "dummy" word + // to preserve data alignment later. + // + // The workaround uses a critical section for precision + // To minimize the time in critical section, we raise the SPI frequency + // to the max possible for the initial preamble to be clocked out + // then we switch to a 'reasonably' slow frequency to be able to reliably + // catch the rising or falling edge by polling. Then we switch back to + // configured frequency + // + + // We want to slow down the clock to help us count edges more + // accurately. Save it first, then slow it down. Also, we will + // pre-calculate a delay for when we need to restore the SPI settings. + // + ui32ClkCfg = AM_REGn(IOMSTR, WORKAROUND_IOM, CLKCFG); + // Get the largest speed we can configure within our rated speed of 16MHz + ui32HiFsel = iom_get_workaround_fsel(16000000); + ui32HiClkCfg = ((ui32ClkCfg & (~AM_REG_IOMSTR_CLKCFG_FSEL_M)) | + AM_BFV(IOMSTR, CLKCFG, FSEL, ui32HiFsel)); + // Switch to Hi Freq + // Need to make sure we wait long enough for the hi clock to be effective + // Delay 2 cycles based on previous frequency + ui32NormalFreq = am_hal_iom_frequency_get(ui32ClkCfg); + AM_REGn(IOMSTR, WORKAROUND_IOM, CLKCFG) = ui32HiClkCfg; + ui32DelayTime = ((2 * AM_HAL_CLKGEN_FREQ_MAX_HZ) / (ui32NormalFreq * 3)); + ((void (*)(uint32_t)) 0x0800009d)(ui32DelayTime); + // + // Remember what frequency we'll be running at.during Hi Phase + // + ui32HiFreq = am_hal_iom_frequency_get(ui32HiClkCfg); + + // + // Validate return value to prevent DIVBY0 errors. + // + am_hal_debug_assert_msg(ui32HiFreq > 0, "Invalid Hi Frequency for IOM."); + + // Get a reasonably slow speed (~1MHz) we can safely poll for the transition + ui32LowFsel = iom_get_workaround_fsel(1000000); + ui32LowClkCfg = ((ui32ClkCfg & (~AM_REG_IOMSTR_CLKCFG_FSEL_M)) | + AM_BFV(IOMSTR, CLKCFG, FSEL, ui32LowFsel)); + + if ( ui32Options & AM_HAL_IOM_RAW ) + { + // + // The transition we care for is on 33rd bit. + // Prepare to delay 27 bits past the start of the transaction + // before getting into polling - to leave some + // margin for compiler related variations + // + ui32DelayTime = ((27 * AM_HAL_CLKGEN_FREQ_MAX_HZ) / (ui32HiFreq * 3)); + + if ( pui32Data[0] & 0x80 ) + { + ui32FirstWord = 0x00000000; + bRising = true; + } + else + { + ui32FirstWord = 0xFFFFFF00; + bRising = false; + } + } + else + { + // + // The transition we care for is on 25th bit. + // Prepare to delay 19 bits past the start of the transaction + // before getting into polling - to leave some + // margin for compiler related variations + // + ui32DelayTime = ((19 * AM_HAL_CLKGEN_FREQ_MAX_HZ) / (ui32HiFreq * 3)); + ui32FirstWord = ((ui32Options & 0xFF00) << 16); + if ( ui32FirstWord & 0x80000000 ) + { + bRising = true; + } + else + { + ui32FirstWord |= 0x00FFFF00; + bRising = false; + } + } + + // + // Now that weve taken care of the offset byte, we can run the + // transaction in RAW mode. + // + ui32Options |= AM_HAL_IOM_RAW; + + ui32NumBytes += 4; + + // + // Figure out how many bytes we can write to the FIFO immediately. + // + ui32TransferSize = (ui32NumBytes <= ui32MaxFifoSize ? ui32NumBytes : + ui32MaxFifoSize); + + am_hal_iom_fifo_write(WORKAROUND_IOM, &ui32FirstWord, 4); + + am_hal_iom_fifo_write(WORKAROUND_IOM, pui32Data, ui32TransferSize - 4); + + // + // Calculate the GPIO to be controlled until the initial shift is + // complete. Make sure we get a valid value. + // + ui32IOMGPIO = iom_calc_gpio(ui32ChipSelect); + am_hal_debug_assert(0xDEADBEEF != ui32IOMGPIO); + + // + // Save the locations and values of the CS pin configuration + // information. + // + pui32CSPadreg = (volatile uint32_t *)AM_HAL_GPIO_PADREG(ui32IOMGPIO); + ui32CSPadregVal = *pui32CSPadreg; + + // + // Switch CS to a GPIO. + // + am_hal_gpio_out_bit_set(ui32IOMGPIO); + am_hal_gpio_pin_config(ui32IOMGPIO, AM_HAL_GPIO_OUTPUT); + + // + // Enable the input buffer on MOSI. + // + am_hal_gpio_pin_config(WORKAROUND_IOM_MOSI_PIN, WORKAROUND_IOM_MOSI_CFG | AM_HAL_PIN_DIR_INPUT); + + // + // Write the GPIO PADKEY register to allow the workaround loop to + // reconfigure chip enable. + // + AM_REGn(GPIO, 0, PADKEY) = AM_REG_GPIO_PADKEY_KEYVAL; + // Preconstruct the command - to save on calculations inside critical section + ui32Command = internal_am_hal_iom_spi_cmd_construct(AM_HAL_IOM_WRITE, + ui32ChipSelect, ui32NumBytes, ui32Options); + internal_iom_workaround_critical(ui32Command, + pui32CSPadreg, ui32CSPadregVal, + ui32DelayTime, ui32ClkCfg, + ui32LowClkCfg, bRising); + + // + // Update the pointer and data counter. + // + ui32NumBytes -= ui32TransferSize; + pui32Data += (ui32TransferSize - 4) >> 2; +} + +//***************************************************************************** +// +//! @brief Implement an iterative spin loop. +//! +//! @param ui32Iterations - Number of iterations to delay. +//! +//! Use this function to implement a CPU busy waiting spin. For Apollo, this +//! delay can be used for timing purposes since for Apollo, each iteration will +//! take 3 cycles. +//! +//! @return None. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +static void __attribute__((naked)) +iom_workaround_loop(uint32_t ui32PadRegVal, volatile uint32_t *pui32PadReg, + bool bRising) +{ + // + // Check to see if this is a "rising edge" or "falling edge" detector. + // + __asm(" cbz r2, falling_edge"); + + // + // Read GPIO pin 44, and loop until it's HIGH. + // + __asm("rising_edge:"); + __asm(" ldr r2, =0x40010084"); + __asm("rising_check_mosi:"); + __asm(" ldr r3, [r2]"); + __asm(" ands r3, r3, #0x1000"); + __asm(" beq rising_check_mosi"); + + // + // Write the PADREG Value to the PADREG register. + // + __asm(" str r0, [r1]"); + __asm(" bx lr"); + + // + // Read GPIO pin 44, and loop until it's LOW. + // + __asm("falling_edge:"); + __asm(" ldr r2, =0x40010084"); + __asm("falling_check_mosi:"); + __asm(" ldr r3, [r2]"); + __asm(" ands r3, r3, #0x1000"); + __asm(" bne falling_check_mosi"); + + // + // Write the PADREG Value to the PADREG register. + // + __asm(" str r0, [r1]"); + __asm(" bx lr"); +} +#endif +#ifdef keil +__asm static void +iom_workaround_loop(uint32_t ui32PadRegVal, volatile uint32_t *pui32PadReg, + bool bRising) +{ + // + // Check to see if this is a "rising edge" or "falling edge" detector. + // + cbz r2, falling_edge + + // + // Read GPIO pin 44, and loop until it's HIGH. + // +rising_edge + ldr r2, =0x40010084 +rising_check_mosi + ldr r3, [r2] + ands r3, r3, #0x1000 + beq rising_check_mosi + + // + // Write the PADREG Value to the PADREG register. + // + str r0, [r1] + bx lr + + // + // Read GPIO pin 44, and loop until it's LOW. + // +falling_edge + ldr r2, =0x40010084 +falling_check_mosi + ldr r3, [r2] + ands r3, r3, #0x1000 + bne falling_check_mosi + + // + // Write the PADREG Value to the PADREG register. + // + str r0, [r1] + bx lr + nop +} +#endif +#ifdef iar +static void +iom_workaround_loop(uint32_t ui32PadRegVal, volatile uint32_t *pui32PadReg, + bool bRising) +{ + // + // Check to see if this is a "rising edge" or "falling edge" detector. + // + asm( + " cbz r2, falling_edge\n" + + // + // Read GPIO pin 44, and loop until it's HIGH. + // + "rising_edge:\n" + " mov32 r2, #0x40010084\n" + "rising_check_mosi:\n" + " ldr r3, [r2]\n" + " ands r3, r3, #0x1000\n" + " beq rising_check_mosi\n" + + // + // Write the PADREG Value to the PADREG register. + // + " str r0, [r1]\n" + " bx lr\n" + + // + // Read GPIO pin 44, and loop until it's LOW. + // + "falling_edge:\n" + " mov32 r2, #0x40010084\n" + "falling_check_mosi:\n" + " ldr r3, [r2]\n" + " ands r3, r3, #0x1000\n" + " bne falling_check_mosi\n" + + // + // Write the PADREG Value to the PADREG register. + // + " str r0, [r1]\n" + " bx lr" + ); +} +#endif + +//***************************************************************************** +// +//! @brief Perform a simple write to the SPI interface. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs SPI writes to a selected SPI device. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_spi_write(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + // + // Validate parameters + // + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to use an IOM module that doesn't exist."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Check to see if queues have been enabled. If they are, we'll actually + // switch to the queued interface. + // + if ( g_psIOMQueue[ui32Module].pui8Data != NULL ) + { + // + // If the queue is on, go ahead and add this transaction to the queue. + // + am_hal_iom_queue_spi_write(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, 0); + + // + // Wait until the transaction actually clears. + // + am_hal_iom_queue_flush(ui32Module); + + // + // At this point, we've completed the transaction, and we can return. + // + return; + } + else + { + // + // Otherwise, we'll just do a polled transaction. + // + am_hal_iom_spi_write_nq(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options); + } +} + +//***************************************************************************** +// +//! @brief Perform simple SPI read operations. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs simple SPI read operations. The caller is +//! responsible for ensuring that the receive buffer is large enough to hold +//! the requested amount of data. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_spi_read(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + // + // Validate parameters + // + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to use an IOM module that doesn't exist."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 4096, "SPI transfer too big."); + + // + // Check to see if queues have been enabled. If they are, we'll actually + // switch to the queued interface. + // + if ( g_psIOMQueue[ui32Module].pui8Data != NULL ) + { + // + // If the queue is on, go ahead and add this transaction to the queue. + // + am_hal_iom_queue_spi_read(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, 0); + + // + // Wait until the transaction actually clears. + // + am_hal_iom_queue_flush(ui32Module); + + // + // At this point, we've completed the transaction, and we can return. + // + return; + } + else + { + // + // Otherwise, just perform a polled transaction. + // + am_hal_iom_spi_read_nq(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options); + } +} + +//***************************************************************************** +// +//! @brief Perform a simple write to the SPI interface (without queuing) +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs SPI writes to a selected SPI device. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_iom_spi_write_nq(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32TransferSize; + uint32_t ui32SpaceInFifo; + uint32_t ui32IntConfig; + uint32_t ui32MaxFifoSize; + uint32_t ui32Status = 1; + + // + // Validate parameters + // + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to use an IOM module that doesn't exist."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 4096, "SPI transfer too big."); + + ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, ui32Module, CFG, FULLDUP)) ? + AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + // + // Wait until any earlier transactions have completed. + // + am_hal_iom_poll_complete(ui32Module); + // + // Disable interrupts so that we don't get any undesired interrupts. + // + ui32IntConfig = AM_REGn(IOMSTR, ui32Module, INTEN); + AM_REGn(IOMSTR, ui32Module, INTEN) = 0; + // Clear CMDCMP status + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // If we're on a B0 part, and we're using IOM4, our first byte coule be + // corrupted, so we need to send a dummy word with chip-select held high to + // get that first byte out of the way. + // + // That operation is tricky and detailed, so we'll call a function to do it + // for us. + // + if ( WORKAROUND_IOM == ui32Module && isRevB0() ) + { + am_hal_iom_workaround_word_write(ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options); + // + // The workaround function is going to a partial transfer for us, but + // we have to keep our own data-tracking variables updated. Here, we're + // subtracting 4 bytes from the effective transfer size to account for + // the 4 bytes of "dummy" word that we sent instead of the actual data. + // + ui32TransferSize = (ui32NumBytes <= (ui32MaxFifoSize - 4) ? ui32NumBytes : + (ui32MaxFifoSize - 4)); + } + else + { + // + // Figure out how many bytes we can write to the FIFO immediately. + // + ui32TransferSize = (ui32NumBytes <= ui32MaxFifoSize ? ui32NumBytes : + ui32MaxFifoSize); + // + // write our first word to the fifo. + // + + am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize); + + // + // Start the write on the bus. + // + am_hal_iom_spi_cmd_run(AM_HAL_IOM_WRITE, ui32Module, ui32ChipSelect, + ui32NumBytes, ui32Options); + } + + // + // Update the pointer and data counter. + // + ui32NumBytes -= ui32TransferSize; + pui32Data += ui32TransferSize >> 2; + + // + // Keep looping until we're out of bytes to send or command complete (error). + // + while ( ui32NumBytes && !AM_BFRn(IOMSTR, ui32Module, INTSTAT, CMDCMP) ) + { + // + // This will always return a multiple of four. + // + ui32SpaceInFifo = am_hal_iom_fifo_empty_slots(ui32Module); + + if ( ui32NumBytes <= ui32SpaceInFifo ) + { + // + // If the entire message will fit in the fifo, prepare to copy + // everything. + // + ui32TransferSize = ui32NumBytes; + } + else + { + // + // If only a portion of the message will fit in the fifo, prepare + // to copy the largest number of 4-byte blocks possible. + // + ui32TransferSize = ui32SpaceInFifo & ~(0x3); + } + + // + // Write this chunk to the fifo. + // + am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize); + + // + // Update the data pointer and bytes-left count. + // + ui32NumBytes -= ui32TransferSize; + pui32Data += ui32TransferSize >> 2; + } + + // + // Make sure CMDCMP was raised with standard timeout + // + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + // + // Re-enable IOM interrupts. Make sure CMDCMP is cleared + // + AM_REGn(IOMSTR, ui32Module, INTCLR) = (ui32IntConfig | AM_REG_IOMSTR_INTSTAT_CMDCMP_M); + AM_REGn(IOMSTR, ui32Module, INTEN) = ui32IntConfig; + + am_hal_debug_assert_msg(ui32Status == 1,"IOM CMDCMP was not seen"); + + // + // Return the status (0 = timeout; 1 = success) + // + return ui32Status; + +} + +//***************************************************************************** +// +//! @brief Perform simple SPI read operations (without queuing). +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs simple SPI read operations. The caller is +//! responsible for ensuring that the receive buffer is large enough to hold +//! the requested amount of data. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_iom_spi_read_nq(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32BytesInFifo; + uint32_t ui32IntConfig; + uint32_t bCmdCmp = false; + uint32_t ui32Status = 1; + + // + // Validate parameters + // + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to use an IOM module that doesn't exist."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 4096, "SPI transfer too big."); + + // + // Wait until the bus is idle, then start the requested READ transfer on + // the physical interface. + // + am_hal_iom_poll_complete(ui32Module); + + // + // Disable interrupts so that we don't get any undesired interrupts. + // + ui32IntConfig = AM_REGn(IOMSTR, ui32Module, INTEN); + + // + // Disable IOM interrupts as we'll be polling + // + AM_REGn(IOMSTR, ui32Module, INTEN) = 0; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // If we're on a B0 part, and we're using IOM4, our first byte coule be + // corrupted, so we need to send a dummy word with chip-select held high to + // get that first byte out of the way. This is only true for spi reads with + // OFFSET values. + // + // That operation is tricky and detailed, so we'll call a function to do it + // for us. + // + if ( (WORKAROUND_IOM == ui32Module) && !(ui32Options & AM_HAL_IOM_RAW) && + isRevB0() ) + { + am_hal_iom_workaround_word_write(ui32ChipSelect, pui32Data, 0, + ui32Options | AM_HAL_IOM_CS_LOW); + + // + // The workaround will send our offset for us, so we can run a RAW + // command after. + // + ui32Options |= AM_HAL_IOM_RAW; + // + // Wait for the dummy word to go out over the bus. + // + // Make sure the command complete has also been raised + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + + // Clear CMDCMP status + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + } + + am_hal_iom_spi_cmd_run(AM_HAL_IOM_READ, ui32Module, ui32ChipSelect, + ui32NumBytes, ui32Options); + + // + // Start a loop to catch the Rx data. + // + while ( ui32NumBytes ) + { + ui32BytesInFifo = am_hal_iom_fifo_full_slots(ui32Module); + + if ( ui32BytesInFifo >= ui32NumBytes ) + { + // + // If the fifo contains our entire message, just copy the whole + // thing out. + // + am_hal_iom_fifo_read(ui32Module, pui32Data, ui32NumBytes); + ui32NumBytes = 0; + } + else if ( ui32BytesInFifo >= 4 ) + { + // + // If the fifo has at least one 32-bit word in it, copy whole + // words out. + // + am_hal_iom_fifo_read(ui32Module, pui32Data, ui32BytesInFifo & ~0x3); + ui32NumBytes -= ui32BytesInFifo & ~0x3; + pui32Data += ui32BytesInFifo >> 2; + } + if ( bCmdCmp == true ) + { + // + // No more data expected. Get out of the loop + // + break; + } + + bCmdCmp = AM_BFRn(IOMSTR, ui32Module, INTSTAT, CMDCMP); + } + + // + // Make sure CMDCMP was raised, + // + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + // + // Re-enable IOM interrupts. Make sure CMDCMP is cleared + // + AM_REGn(IOMSTR, ui32Module, INTCLR) = (ui32IntConfig | AM_REG_IOMSTR_INTSTAT_CMDCMP_M); + AM_REGn(IOMSTR, ui32Module, INTEN) = ui32IntConfig; + + am_hal_debug_assert_msg(ui32Status == 1,"IOM CMDCMP was not seen"); + + // + // Return the status (0 = timeout; 1 = success) + // + return ui32Status; +} + +//***************************************************************************** +// +//! @brief Perform a non-blocking write to the SPI interface. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional SPI transfer options. +//! @param pfnCallback - Function to call when the transaction completes. +//! +//! This function performs SPI writes to the selected SPI device. +//! +//! This function call is a non-blocking implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. The +//! caller will need to make sure that \e am_hal_iom_int_service() is called +//! for IOM FIFO interrupt events and "command complete" interrupt events. The +//! \e am_hal_iom_int_service() function will refill the FIFO as necessary and +//! call the \e pfnCallback function when the transaction is finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_spi_write_nb(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32TransferSize; + uint32_t ui32MaxFifoSize; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 4096, "SPI transfer too big."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, ui32Module, CFG, FULLDUP)) ? + AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + + // + // Wait until the bus is idle + // + am_hal_iom_poll_complete(ui32Module); + + // + // Need to mark IOM busy to avoid another transaction to be scheduled. + // This is to take care of a race condition in Queue mode, where the IDLE + // set is not a guarantee that the CMDCMP has been received + // + g_bIomBusy[ui32Module] = true; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // Check to see if we need to do the workaround. + // + if ( WORKAROUND_IOM == ui32Module && isRevB0() ) + { + // + // Figure out how many bytes we can write to the FIFO immediately, + // accounting for the extra word from the workaround. + // + ui32TransferSize = (ui32NumBytes <= (ui32MaxFifoSize - 4) ? ui32NumBytes : + (ui32MaxFifoSize - 4)); + + // + // Prepare the global IOM buffer structure. + // + g_psIOMBuffers[ui32Module].ui32State = BUFFER_SENDING; + g_psIOMBuffers[ui32Module].pui32Data = pui32Data + (ui32TransferSize / 4); + g_psIOMBuffers[ui32Module].ui32BytesLeft = ui32NumBytes - ui32TransferSize; + g_psIOMBuffers[ui32Module].pfnCallback = pfnCallback; + g_psIOMBuffers[ui32Module].ui32Options = ui32Options; + + // + // Start the write on the bus using the workaround. This includes both + // the command write and the first fifo write, so we won't need to do + // either of those things manually. + // + am_hal_iom_workaround_word_write(ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options); + } + else + { + // + // Figure out how many bytes we can write to the FIFO immediately. + // + ui32TransferSize = (ui32NumBytes <= ui32MaxFifoSize ? ui32NumBytes : + ui32MaxFifoSize); + + if ( am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize) > 0 ) + { + // + // Prepare the global IOM buffer structure. + // + g_psIOMBuffers[ui32Module].ui32State = BUFFER_SENDING; + g_psIOMBuffers[ui32Module].pui32Data = pui32Data; + g_psIOMBuffers[ui32Module].ui32BytesLeft = ui32NumBytes; + g_psIOMBuffers[ui32Module].pfnCallback = pfnCallback; + g_psIOMBuffers[ui32Module].ui32Options = ui32Options; + + // + // Update the pointer and the byte counter based on the portion of + // the transfer we just sent to the fifo. + // + g_psIOMBuffers[ui32Module].ui32BytesLeft -= ui32TransferSize; + g_psIOMBuffers[ui32Module].pui32Data += (ui32TransferSize / 4); + + // + // Start the write on the bus. + // + am_hal_iom_spi_cmd_run(AM_HAL_IOM_WRITE, ui32Module, ui32ChipSelect, + ui32NumBytes, ui32Options); + } + } +} + +//***************************************************************************** +// +//! @brief Perform a non-blocking SPI read. +//! +//! @param ui32Module - Module number for the IOM. +//! @param ui32ChipSelect - Chip select number of the target device. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional SPI transfer options. +//! @param pfnCallback - Function to call when the transaction completes. +//! +//! This function performs SPI reads to a selected SPI device. +//! +//! This function call is a non-blocking implementation. It will start the SPI +//! transaction on the bus and store a pointer for the destination for the read +//! data, but it will not wait for the SPI transaction to finish. The caller +//! will need to make sure that \e am_hal_iom_int_service() is called for IOM +//! FIFO interrupt events and "command complete" interrupt events. The \e +//! am_hal_iom_int_service() function will empty the FIFO as necessary, +//! transfer the data to the \e pui32Data buffer, and call the \e pfnCallback +//! function when the transaction is finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_iom_spi_read_nb(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32IntConfig; + uint32_t ui32Status = 1; + + // + // Validate parameters + // + am_hal_debug_assert_msg(ui32Module < AM_REG_IOMSTR_NUM_MODULES, + "Trying to use an IOM module that doesn't exist."); + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 4096, "SPI transfer too big."); + + // + // Wait until the bus is idle + // + am_hal_iom_poll_complete(ui32Module); + + // + // Need to mark IOM busy to avoid another transaction to be scheduled. + // This is to take care of a race condition in Queue mode, where the IDLE + // set is not a guarantee that the CMDCMP has been received + // + + g_bIomBusy[ui32Module] = true; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // If we're on a B0 part, and we're using IOM4, our first byte coule be + // corrupted, so we need to send a dummy word with chip-select held high to + // get that first byte out of the way. This is only true for spi reads with + // OFFSET values. + // + // That operation is tricky and detailed, so we'll call a function to do it + // for us. + // + if ( (WORKAROUND_IOM == ui32Module) && !(ui32Options & AM_HAL_IOM_RAW) && + isRevB0() ) + { + // + // We might mess up the interrupt handler behavior if we allow this + // polled transaction to complete with interrupts enabled. We'll + // briefly turn them off here. + // + ui32IntConfig = AM_REGn(IOMSTR, 4, INTEN); + AM_REGn(IOMSTR, 4, INTEN) = 0; + + am_hal_iom_workaround_word_write(ui32ChipSelect, pui32Data, + 0, ui32Options | AM_HAL_IOM_CS_LOW); + + // + // The workaround will send our offset for us, so we can run a RAW + // command after. + // + ui32Options |= AM_HAL_IOM_RAW; + + // + // Wait for the dummy word to go out over the bus. + // + // Make sure the command complete has also been raised + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + // + // Re-mark IOM as busy + // + + g_bIomBusy[ui32Module] = true; + + // + // Re-enable IOM interrupts. Make sure CMDCMP is cleared + // + AM_REGn(IOMSTR, 4, INTCLR) = (ui32IntConfig | AM_REG_IOMSTR_INTSTAT_CMDCMP_M); + AM_REGn(IOMSTR, 4, INTEN) = ui32IntConfig; + } + + // + // Prepare the global IOM buffer structure. + // + g_psIOMBuffers[ui32Module].ui32State = BUFFER_RECEIVING; + g_psIOMBuffers[ui32Module].pui32Data = pui32Data; + g_psIOMBuffers[ui32Module].ui32BytesLeft = ui32NumBytes; + g_psIOMBuffers[ui32Module].pfnCallback = pfnCallback; + g_psIOMBuffers[ui32Module].ui32Options = ui32Options; + + // + // Start the read transaction on the bus. + // + am_hal_iom_spi_cmd_run(AM_HAL_IOM_READ, ui32Module, ui32ChipSelect, + ui32NumBytes, ui32Options); + + am_hal_debug_assert_msg(ui32Status == 1,"IOM CMDCMP was not seen"); + + return ui32Status; +} + +static uint32_t +internal_am_hal_iom_spi_cmd_construct(uint32_t ui32Operation, + uint32_t ui32ChipSelect, + uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32Command; + // + // Start building the command from the operation parameter. + // + ui32Command = ui32Operation; + + // + // Set the transfer length (the length field is split, so this requires + // some swizzling). + // + ui32Command |= ((ui32NumBytes & 0xF00) << 15); + ui32Command |= (ui32NumBytes & 0xFF); + + // + // Set the chip select number. + // + ui32Command |= ((ui32ChipSelect << 16) & 0x00070000); + + // + // Finally, OR in the rest of the options. This mask should make sure that + // erroneous option values won't interfere with the other transfer + // parameters. + // + ui32Command |= ui32Options & 0x5C00FF00; + return ui32Command; +} +//***************************************************************************** +// +//! @brief Runs a SPI "command" through the IO master. +//! +//! @param ui32Operation - SPI action to be performed. +//! +//! @param psDevice - Structure containing information about the slave device. +//! +//! @param ui32NumBytes - Number of bytes to move (transmit or receive) with +//! this command. +//! +//! @param ui32Options - Additional SPI options to apply to this command. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_spi_cmd_run(uint32_t ui32Operation, uint32_t ui32Module, + uint32_t ui32ChipSelect, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32Command; + + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + ui32Command = internal_am_hal_iom_spi_cmd_construct(ui32Operation, + ui32ChipSelect, ui32NumBytes, ui32Options); + + + // + // Write the complete command word to the IOM command register. + // + AM_REGn(IOMSTR, ui32Module, CMD) = ui32Command; +} + +//***************************************************************************** +// +//! @brief Perform a simple write to the I2C interface (without queuing) +//! +//! @param ui32Module - Module number for the IOM. +//! @param ui32BusAddress - I2C address of the target device. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional I2C transfer options. +//! +//! This function performs I2C writes to a selected I2C device. +//! +//! This function call is a blocking implementation. It will write as much +//! data to the FIFO as possible immediately, and then refill the FIFO as data +//! is transmiitted. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui32Data array. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_iom_i2c_write_nq(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32TransferSize; + uint32_t ui32SpaceInFifo; + uint32_t ui32IntConfig; + uint32_t ui32MaxFifoSize; + uint32_t ui32Status = 1; + + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // Return. + // + return 0; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, ui32Module, CFG, FULLDUP)) ? + AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + + // + // Wait until any earlier transactions have completed. + // + am_hal_iom_poll_complete(ui32Module); + + // + // Disable interrupts so that we don't get any undesired interrupts. + // + ui32IntConfig = AM_REGn(IOMSTR, ui32Module, INTEN); + AM_REGn(IOMSTR, ui32Module, INTEN) = 0; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // Figure out how many bytes we can write to the FIFO immediately. + // + ui32TransferSize = (ui32NumBytes <= ui32MaxFifoSize ? ui32NumBytes : + ui32MaxFifoSize); + + am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize); + + // + // Start the write on the bus. + // + am_hal_iom_i2c_cmd_run(AM_HAL_IOM_WRITE, ui32Module, ui32BusAddress, + ui32NumBytes, ui32Options); + + // + // Update the pointer and data counter. + // + ui32NumBytes -= ui32TransferSize; + pui32Data += ui32TransferSize >> 2; + + // + // Keep looping until we're out of bytes to send or command complete (error). + // + while ( ui32NumBytes && !AM_BFRn(IOMSTR, ui32Module, INTSTAT, CMDCMP) ) + { + // + // This will always return a multiple of four. + // + ui32SpaceInFifo = am_hal_iom_fifo_empty_slots(ui32Module); + + if ( ui32NumBytes <= ui32SpaceInFifo ) + { + // + // If the entire message will fit in the fifo, prepare to copy + // everything. + // + ui32TransferSize = ui32NumBytes; + } + else + { + // + // If only a portion of the message will fit in the fifo, prepare + // to copy the largest number of 4-byte blocks possible. + // + ui32TransferSize = ui32SpaceInFifo; + } + + // + // Write this chunk to the fifo. + // + am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize); + + // + // Update the data pointer and bytes-left count. + // + ui32NumBytes -= ui32TransferSize; + pui32Data += ui32TransferSize >> 2; + } + + // + // Make sure CMDCMP was raised, + // + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + // + // Re-enable IOM interrupts. Make sure CMDCMP is cleared + // + AM_REGn(IOMSTR, ui32Module, INTCLR) = (ui32IntConfig | AM_REG_IOMSTR_INTSTAT_CMDCMP_M); + AM_REGn(IOMSTR, ui32Module, INTEN) = ui32IntConfig; + + am_hal_debug_assert_msg(ui32Status == 1,"IOM CMDCMP was not seen"); + + // + // Return the status (0 = timeout; 1 = success) + // + return ui32Status; +} + +//***************************************************************************** +// +//! @brief Perform simple I2C read operations (without queuing). +//! +//! @param ui32Module - Module number for the IOM. +//! @param ui32BusAddress - I2C address of the target device. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional I2C transfer options. +//! +//! This function performs an I2C read to a selected I2C device. +//! +//! This function call is a blocking implementation. It will read as much +//! data from the FIFO as possible immediately, and then re-read the FIFO as more +//! data is available. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_iom_i2c_read_nq(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32BytesInFifo; + uint32_t ui32IntConfig; + uint32_t bCmdCmp = false; + uint32_t ui32Status = 1; + + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // Return. + // + return 0; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + // + // Wait until the bus is idle + // + am_hal_iom_poll_complete(ui32Module); + + // + // Disable interrupts so that we don't get any undesired interrupts. + // + ui32IntConfig = AM_REGn(IOMSTR, ui32Module, INTEN); + AM_REGn(IOMSTR, ui32Module, INTEN) = 0; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + am_hal_iom_i2c_cmd_run(AM_HAL_IOM_READ, ui32Module, ui32BusAddress, + ui32NumBytes, ui32Options); + + // + // Start a loop to catch the Rx data. + // + while ( ui32NumBytes ) + { + ui32BytesInFifo = am_hal_iom_fifo_full_slots(ui32Module); + + if ( ui32BytesInFifo >= ui32NumBytes ) + { + // + // If the fifo contains our entire message, just copy the whole + // thing out. + // + am_hal_iom_fifo_read(ui32Module, pui32Data, ui32NumBytes); + ui32NumBytes = 0; + } + else if ( ui32BytesInFifo >= 4 ) + { + // + // If the fifo has at least one 32-bit word in it, copy whole + // words out. + // + am_hal_iom_fifo_read(ui32Module, pui32Data, ui32BytesInFifo & ~0x3); + + ui32NumBytes -= ui32BytesInFifo & ~0x3; + pui32Data += ui32BytesInFifo >> 2; + } + + if ( bCmdCmp == true ) + { + // No more data expected - exit out of loop + break; + } + + bCmdCmp = AM_BFRn(IOMSTR, ui32Module, INTSTAT, CMDCMP); + } + + // + // Make sure CMDCMP was raised, + // + ui32Status = am_util_wait_status_change(ui32StatusTimeout[ui32Module], + AM_REG_IOMSTRn(ui32Module) + AM_REG_IOMSTR_INTSTAT_O, + AM_REG_IOMSTR_INTEN_CMDCMP_M, AM_REG_IOMSTR_INTEN_CMDCMP_M); + + // + // Re-enable IOM interrupts. Make sure CMDCMP is cleared + // + AM_REGn(IOMSTR, ui32Module, INTCLR) = (ui32IntConfig | AM_REG_IOMSTR_INTSTAT_CMDCMP_M); + AM_REGn(IOMSTR, ui32Module, INTEN) = ui32IntConfig; + + am_hal_debug_assert_msg(ui32Status == 1,"IOM CMDCMP was not seen"); + + // + // Return the status (0 = timeout; 1 = success) + // + return ui32Status; +} + +//***************************************************************************** +// +//! @brief Perform a simple write to the I2C interface. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32BusAddress - I2C bus address for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional options +//! +//! Performs a write to the I2C interface using the provided parameters. +//! +//! See the "Command Options" section for parameters that may be ORed together +//! and used in the \b ui32Options parameter. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_i2c_write(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // Return. + // + return; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + // + // Check to see if queues have been enabled. If they are, we'll actually + // switch to the queued interface. + // + if ( g_psIOMQueue[ui32Module].pui8Data != NULL ) + { + // + // If the queue is on, go ahead and add this transaction to the queue. + // + am_hal_iom_queue_i2c_write(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options, 0); + + // + // Wait until the transaction actually clears. + // + am_hal_iom_queue_flush(ui32Module); + + // + // At this point, we've completed the transaction, and we can return. + // + return; + } + else + { + // + // Otherwise, we'll just do a polled transaction. + // + am_hal_iom_i2c_write_nq(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options); + } +} + +//***************************************************************************** +// +//! @brief Perform simple I2C read operations. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32BusAddress - I2C bus address for this transaction. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional I2C transfer options. +//! +//! This function performs simple I2C read operations. The caller is +//! responsible for ensuring that the receive buffer is large enough to hold +//! the requested amount of data. If \e bPolled is true, this function will +//! block until all of the requested data has been received and placed in the +//! user-supplied buffer. Otherwise, the function will execute the I2C read +//! command and return immediately. The user-supplied buffer will be filled +//! with the received I2C data as it comes in over the physical interface, and +//! the "command complete" interrupt bit will become active once the entire +//! message is available. +//! +//! See the "Command Options" section for parameters that may be ORed together +//! and used in the \b ui32Options parameter. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_i2c_read(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // Return. + // + return; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + // + // Check to see if queues have been enabled. If they are, we'll actually + // switch to the queued interface. + // + if ( g_psIOMQueue[ui32Module].pui8Data != NULL ) + { + // + // If the queue is on, go ahead and add this transaction to the queue. + // + am_hal_iom_queue_i2c_read(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options, 0); + + // + // Wait until the transaction actually clears. + // + am_hal_iom_queue_flush(ui32Module); + + // + // At this point, we've completed the transaction, and we can return. + // + return; + } + else + { + // + // Otherwise, just perform a polled transaction. + // + am_hal_iom_i2c_read_nq(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options); + } +} + +//***************************************************************************** +// +//! @brief Perform a non-blocking write to the I2C interface. +//! +//! @param ui32Module - Module number for the IOM. +//! @param ui32BusAddress - I2C address of the target device. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional I2C transfer options. +//! @param pfnCallback - Function to call when the transaction completes. +//! +//! This function performs I2C writes to a selected I2C device. +//! +//! This function call is a non-blocking implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. The +//! caller will need to make sure that \e am_hal_iom_int_service() is called +//! for IOM FIFO interrupt events and "command complete" interrupt events. The +//! \e am_hal_iom_int_service() function will refill the FIFO as necessary and +//! call the \e pfnCallback function when the transaction is finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui32Data array. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_i2c_write_nb(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32TransferSize; + uint32_t ui32MaxFifoSize; + + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_send(ui32BusAddress << 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // The I2C bit-bang interface is actually a blocking transfer, and it + // doesn't trigger the interrupt handler, so we have to call the + // callback function manually. + // + if ( pfnCallback ) + { + pfnCallback(); + } + // + // Return. + // + return; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, ui32Module, CFG, FULLDUP)) ? + AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + + // + // Figure out how many bytes we can write to the FIFO immediately. + // + ui32TransferSize = (ui32NumBytes <= ui32MaxFifoSize ? ui32NumBytes : + ui32MaxFifoSize); + + // + // Wait until any earlier transactions have completed, and then write our + // first word to the fifo. + // + am_hal_iom_poll_complete(ui32Module); + + // Need to mark IOM busy to avoid another transaction to be scheduled. + // This is to take care of a race condition in Queue mode, where the IDLE + // set is not a guarantee that the CMDCMP has been received + g_bIomBusy[ui32Module] = true; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + if ( am_hal_iom_fifo_write(ui32Module, pui32Data, ui32TransferSize) > 0 ) + { + // + // Prepare the global IOM buffer structure. + // + g_psIOMBuffers[ui32Module].ui32State = BUFFER_SENDING; + g_psIOMBuffers[ui32Module].pui32Data = pui32Data; + g_psIOMBuffers[ui32Module].ui32BytesLeft = ui32NumBytes; + g_psIOMBuffers[ui32Module].pfnCallback = pfnCallback; + + // + // Update the pointer and the byte counter based on the portion of the + // transfer we just sent to the fifo. + // + g_psIOMBuffers[ui32Module].ui32BytesLeft -= ui32TransferSize; + g_psIOMBuffers[ui32Module].pui32Data += (ui32TransferSize / 4); + + // + // Start the write on the bus. + // + am_hal_iom_i2c_cmd_run(AM_HAL_IOM_WRITE, ui32Module, ui32BusAddress, + ui32NumBytes, ui32Options); + } +} + +//***************************************************************************** +// +//! @brief Perform a non-blocking I2C read. +//! +//! @param ui32Module - Module number for the IOM. +//! @param ui32ChipSelect - I2C address of the target device. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional I2C transfer options. +//! @param pfnCallback - Function to call when the transaction completes. +//! +//! This function performs an I2C read to a selected I2C device. +//! +//! This function call is a non-blocking implementation. It will start the I2C +//! transaction on the bus and store a pointer for the destination for the read +//! data, but it will not wait for the I2C transaction to finish. The caller +//! will need to make sure that \e am_hal_iom_int_service() is called for IOM +//! FIFO interrupt events and "command complete" interrupt events. The \e +//! am_hal_iom_int_service() function will empty the FIFO as necessary, +//! transfer the data to the \e pui32Data buffer, and call the \e pfnCallback +//! function when the transaction is finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_i2c_read_nb(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback) +{ + // + // Validate parameters + // + if ( ui32Module > AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Redirect to the bit-bang interface if the module number matches the + // software I2C module. + // + if ( ui32Module == AM_HAL_IOM_I2CBB_MODULE ) + { + if ( ui32Options & AM_HAL_IOM_RAW ) + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, 0, false, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + else + { + am_hal_i2c_bit_bang_receive((ui32BusAddress << 1) | 1, ui32NumBytes, + (uint8_t *)pui32Data, + ((ui32Options & 0xFF00) >> 8), + true, + (ui32Options & AM_HAL_IOM_NO_STOP)); + } + + // + // The I2C bit-bang interface is actually a blocking transfer, and it + // doesn't trigger the interrupt handler, so we have to call the + // callback function manually. + // + if ( pfnCallback ) + { + pfnCallback(); + } + + // + // Return. + // + return; + } + + // + // Make sure the transfer isn't too long for the hardware to support. + // + am_hal_debug_assert_msg(ui32NumBytes < 256, "I2C transfer too big."); + + // + // Wait until the bus is idle + // + am_hal_iom_poll_complete(ui32Module); + + // + // Need to mark IOM busy to avoid another transaction to be scheduled. + // This is to take care of a race condition in Queue mode, where the IDLE + // set is not a guarantee that the CMDCMP has been received + // + g_bIomBusy[ui32Module] = true; + + // + // Clear CMDCMP status + // + AM_BFWn(IOMSTR, ui32Module, INTCLR, CMDCMP, 1); + + // + // Prepare the global IOM buffer structure. + // + g_psIOMBuffers[ui32Module].ui32State = BUFFER_RECEIVING; + g_psIOMBuffers[ui32Module].pui32Data = pui32Data; + g_psIOMBuffers[ui32Module].ui32BytesLeft = ui32NumBytes; + g_psIOMBuffers[ui32Module].pfnCallback = pfnCallback; + + // + // Start the read transaction on the bus. + // + am_hal_iom_i2c_cmd_run(AM_HAL_IOM_READ, ui32Module, ui32BusAddress, + ui32NumBytes, ui32Options); +} + +//***************************************************************************** +// +//! @brief Runs a I2C "command" through the IO master. +//! +//! @param ui32Operation - I2C action to be performed. This should either be +//! AM_HAL_IOM_WRITE or AM_HAL_IOM_READ. +//! @param psDevice - Structure containing information about the slave device. +//! @param ui32NumBytes - Number of bytes to move (transmit or receive) with +//! this command. +//! @param ui32Options - Additional I2C options to apply to this command. +//! +//! This function may be used along with am_hal_iom_fifo_write and +//! am_hal_iom_fifo_read to perform more complex I2C reads and writes. This +//! function +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_i2c_cmd_run(uint32_t ui32Operation, uint32_t ui32Module, + uint32_t ui32BusAddress, uint32_t ui32NumBytes, + uint32_t ui32Options) +{ + uint32_t ui32Command; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Start building the command from the operation parameter. + // + ui32Command = ui32Operation; + + // + // Set the transfer length. + // + ui32Command |= (ui32NumBytes & 0xFF); + + // + // Set the chip select number. + // + ui32Command |= ((ui32BusAddress << 16) & 0x03FF0000); + + // + // Finally, OR in the rest of the options. This mask should make sure that + // erroneous option values won't interfere with the other transfer + // parameters. + // + ui32Command |= (ui32Options & 0x5C00FF00); + + // + // Write the complete command word to the IOM command register. + // + AM_REGn(IOMSTR, ui32Module, CMD) = ui32Command; +} + +//***************************************************************************** +// +//! @brief Sets the repeat count for the next IOM command. +//! +//! @param ui32Module is the IOM module number. +//! @param ui32CmdCount is the number of times the next command should be +//! executed. +//! +//! @note This function is not compatible with the am_hal_iom_spi_read/write() +//! or am_hal_iom_i2c_read/write() functions. Instead, you will need to use the +//! am_hal_iom_fifo_read/write() functions and the am_hal_iom_spi/i2c_cmd_run() +//! functions. +//! +//! Example usage: +//! @code +//! +//! // +//! // Create a buffer and add 3 bytes of data to it. +//! // +//! am_hal_iom_buffer(3) psBuffer; +//! psBuffer.bytes[0] = 's'; +//! psBuffer.bytes[1] = 'p'; +//! psBuffer.bytes[2] = 'i'; +//! +//! // +//! // Send three different bytes to the same SPI register on a remote device. +//! // +//! am_hal_iom_fifo_write(ui32Module, psBuffer.words, 3); +//! +//! am_hal_command_repeat_set(ui32Module, 3); +//! +//! am_hal_iom_spi_cmd_run(AM_HAL_IOM_WRITE, psDevice, 1, +//! AM_HAL_IOM_OFFSET(0x5)); +//! +//! // +//! // The sequence "0x5, 's', 0x5, 'p', 0x5, 'i'" should be written to the SPI +//! // bus. +//! // +//! +//! @endcode +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_command_repeat_set(uint32_t ui32Module, uint32_t ui32CmdCount) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + AM_REGn(IOMSTR, ui32Module, CMDRPT) = ui32CmdCount; +} + +//***************************************************************************** +// +//! @brief Writes data to the IOM FIFO. +//! +//! @param ui32Module - Selects the IOM module to use (zero or one). +//! @param pui32Data - Pointer to an array of the data to be written. +//! @param ui32NumBytes - Number of BYTES to copy into the FIFO. +//! +//! This function copies data from the array \e pui32Data into the IOM FIFO. +//! This prepares the data to eventually be sent as SPI or I2C data by an IOM +//! "command". +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +//! +//! @note This function may be used to write partial or complete SPI or I2C +//! messages into the IOM FIFO. When writing partial messages to the FIFO, make +//! sure that the number of bytes written is a multiple of four. Only the last +//! 'part' of a message may consist of a number of bytes that is not a multiple +//! of four. If this rule is not followed, the IOM will not be able to send +//! these bytes correctly. +//! +//! @return Number of bytes actually written to the FIFO. +// +//***************************************************************************** +uint32_t +am_hal_iom_fifo_write(uint32_t ui32Module, uint32_t *pui32Data, + uint32_t ui32NumBytes) +{ + uint32_t ui32Index; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + // + // Make sure we check the number of bytes we're writing to the FIFO. + // + am_hal_debug_assert_msg((am_hal_iom_fifo_empty_slots(ui32Module) >= ui32NumBytes), + "The fifo couldn't fit the requested number of bytes"); + + // + // Loop over the words in the array until we have the correct number of + // bytes. + // + for ( ui32Index = 0; (4 * ui32Index) < ui32NumBytes; ui32Index++ ) + { + // + // Write the word to the FIFO. + // + AM_REGn(IOMSTR, ui32Module, FIFO) = pui32Data[ui32Index]; + } + + return ui32NumBytes; +} + +//***************************************************************************** +// +//! @brief Reads data from the IOM FIFO. +//! +//! @param ui32Module - Selects the IOM module to use (zero or one). +//! @param pui32Data - Pointer to an array where the FIFO data will be copied. +//! @param ui32NumBytes - Number of bytes to copy into array. +//! +//! This function copies data from the IOM FIFO into the array \e pui32Data. +//! This is how input data from SPI or I2C transactions may be retrieved. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This function will pack the individual bytes from the physical interface +//! into 32-bit words, which are then placed into the \e pui32Data array. Only +//! the first \e ui32NumBytes bytes in this array will contain valid data. +//! +//! @return Number of bytes read from the fifo. +// +//***************************************************************************** +uint32_t +am_hal_iom_fifo_read(uint32_t ui32Module, uint32_t *pui32Data, + uint32_t ui32NumBytes) +{ + am_hal_iom_buffer(4) sTempBuffer; + uint32_t i, j, ui32NumWords, ui32Leftovers; + uint8_t *pui8Data; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + // + // Make sure we check the number of bytes we're reading from the FIFO. + // + am_hal_debug_assert_msg((am_hal_iom_fifo_full_slots(ui32Module) >= ui32NumBytes), + "The fifo doesn't contain the requested number of bytes."); + + // + // Figure out how many whole words we're reading from the fifo, and how + // many bytes will be left over when we're done. + // + ui32NumWords = ui32NumBytes / 4; + ui32Leftovers = ui32NumBytes - (ui32NumWords * 4); + + // + // Copy out as many full words as we can. + // + for ( i = 0; i < ui32NumWords; i++ ) + { + // + // Copy data out of the FIFO, one word at a time. + // + pui32Data[i] = AM_REGn(IOMSTR, ui32Module, FIFO); + } + + // + // If there were leftovers, we'll copy them carefully. Pull the last word + // from the fifo (there should only be one) into a temporary buffer. Also, + // create an 8-bit pointer to help us copy the remaining bytes one at a + // time. + // + // Note: If the data buffer we were given was truly a word pointer like the + // definition requests, we wouldn't need to do this. It's possible to call + // this function with a re-cast or packed pointer instead though. If that + // happens, we want to be careful not to overwrite any data that might be + // sitting just past the end of the destination array. + // + if ( ui32Leftovers ) + { + sTempBuffer.words[0] = AM_REGn(IOMSTR, ui32Module, FIFO); + pui8Data = (uint8_t *) (&pui32Data[i]); + + // + // If we had leftover bytes, copy them out one byte at a time. + // + for ( j = 0; j < ui32Leftovers; j++ ) + { + pui8Data[j] = sTempBuffer.bytes[j]; + } + } + + return ui32NumBytes; +} + +//***************************************************************************** +// +//! @brief Check amount of empty space in the IOM fifo. +//! +//! @param ui32Module - Module number of the IOM whose fifo should be checked. +//! +//! Returns the number of bytes that could be written to the IOM fifo without +//! causing an overflow. +//! +//! @return Amount of space available in the fifo (in bytes). +// +//***************************************************************************** +uint8_t +am_hal_iom_fifo_empty_slots(uint32_t ui32Module) +{ + uint32_t ui32MaxFifoSize; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + ui32MaxFifoSize = ((0 == AM_BFRn(IOMSTR, ui32Module, CFG, FULLDUP)) ? AM_HAL_IOM_MAX_FIFO_SIZE : AM_HAL_IOM_MAX_FIFO_SIZE / 2); + + // + // Calculate the FIFO Remaining from the FIFO size. This will be different + // depending on whether the IOM is configured for half-duplex or + // full-duplex. + // + return (ui32MaxFifoSize - AM_BFRn(IOMSTR, ui32Module, FIFOPTR, FIFOSIZ)) & (~0x3); +} + +//***************************************************************************** +// +//! @brief Check to see how much data is in the IOM fifo. +//! +//! @param ui32Module - Module number of the IOM whose fifo should be checked. +//! +//! Returns the number of bytes of data that are currently in the IOM fifo. +//! +//! @return Number of bytes in the fifo. +// +//***************************************************************************** +uint8_t +am_hal_iom_fifo_full_slots(uint32_t ui32Module) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + return AM_BFRn(IOMSTR, ui32Module, FIFOPTR, FIFOSIZ); +} + +//***************************************************************************** +// +//! @brief Wait for the current IOM command to complete. +//! +//! @param ui32Module - The module number of the IOM to use. +//! +//! This function polls until the IOM bus becomes idle. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_poll_complete(uint32_t ui32Module) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Poll on the IDLE bit in the status register. + // + while ( g_bIomBusy[ui32Module] ); +} + +//***************************************************************************** +// +//! @brief Returns the contents of the IOM status register. +//! +//! @param ui32Module IOM instance to check the status of. +//! +//! This function is just a wrapper around the IOM status register. +//! +//! @return 32-bit contents of IOM status register. +// +//***************************************************************************** +uint32_t +am_hal_iom_status_get(uint32_t ui32Module) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + return AM_REGn(IOMSTR, ui32Module, STATUS); +} + +//***************************************************************************** +// +//! @brief Returns current error state of the IOM. +//! +//! @param ui32Module IOM instance to check the status of. +//! +//! This function returns status indicating whether the IOM has incurred any +//! errors or not. +//! +//! @return 0 if all is well. +//! Otherwise error status as a bitmask of: +//! AM_HAL_IOM_ERR_INVALID_MODULE +//! AM_HAL_IOM_INT_ARB Another master initiated an operation +//! simultaenously and the IOM lost. Or +//! the IOM started an operation but found +//! SDA already low. +//! AM_HAL_IOM_INT_START A START from another master detected. +//! SW must wait for STOP before continuing. +//! AM_HAL_IOM_INT_ICMD Attempt to issue a CMD while another +//! CMD was already in progress, or issue a +//! non-zero-len write CMD with empty FIFO. +//! AM_HAL_IOM_INT_IACC Attempt to read the FIFO on a write. Or +//! an attempt to write the FIFO on a read. +//! AM_HAL_IOM_INT_NAK Expected ACK from slave not received. +//! AM_HAL_IOM_INT_FOVFL Attempt to write the FIFO while full +//! (FIFOSIZ > 124). +//! AM_HAL_IOM_INT_FUNDFL Attempt to read FIFO when empty (that is +//! FIFOSIZ < 4). +//! Note - see the datasheet text for full explanations of the INT errs. +// +//***************************************************************************** +uint32_t +am_hal_iom_error_status_get(uint32_t ui32Module) +{ + uint32_t ui32intstat = 0; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + // + // AM_HAL_IOM_ERR_INVALID_MODULE is defined as an unused interrupt bit. + // + return AM_HAL_IOM_ERR_INVALID_MODULE; + } + + if ( AM_REGn(IOMSTR, ui32Module, STATUS) & AM_REG_IOMSTR_STATUS_ERR_ERROR ) + { + // + // The IOM is currently indicating an error condition. + // Let's figure out what is going on. + // + ui32intstat = AM_REGn(IOMSTR, ui32Module, INTSTAT); + + // + // Filter out non-error bits. + // + ui32intstat &= AM_REG_IOMSTR_INTSTAT_ARB_M | + AM_REG_IOMSTR_INTSTAT_START_M | + AM_REG_IOMSTR_INTSTAT_ICMD_M | + AM_REG_IOMSTR_INTSTAT_IACC_M | + AM_REG_IOMSTR_INTSTAT_NAK_M | + AM_REG_IOMSTR_INTSTAT_FOVFL_M | + AM_REG_IOMSTR_INTSTAT_FUNDFL_M; + } + + return ui32intstat; +} + +//***************************************************************************** +// +//! @brief Service interrupts from the IOM. +//! +//! @param ui32Status is the IOM interrupt status as returned from +//! am_hal_iom_int_status_get() +//! +//! This function performs the necessary operations to facilitate non-blocking +//! IOM writes and reads. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_iom_int_service(uint32_t ui32Module, uint32_t ui32Status) +{ + am_hal_iom_nb_buffer *psBuffer; + uint32_t ui32NumBytes; + uint32_t ui32SpaceInFifo; + uint32_t thresh; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + // + // Find the buffer information for the chosen IOM module. + // + psBuffer = &g_psIOMBuffers[ui32Module]; + + // + // Figure out what type of interrupt this was. + // + if ( ui32Status & AM_HAL_IOM_INT_CMDCMP ) + { + // + // Need to mark IOM Free + // + g_bIomBusy[ui32Module] = false; + + // + // If we're not in the middle of a non-blocking call right now, there's + // nothing for this routine to do. + // + if ( psBuffer->ui32State == BUFFER_IDLE ) + { + return; + } + + // + // If a command just completed, we need to transfer all available data. + // + if ( psBuffer->ui32State == BUFFER_RECEIVING ) + { + // + // If we were receiving, we need to copy any remaining data out of + // the IOM FIFO before calling the callback. + // + ui32NumBytes = am_hal_iom_fifo_full_slots(ui32Module); + am_hal_iom_fifo_read(ui32Module, psBuffer->pui32Data, ui32NumBytes); + } + + // + // A command complete event also means that we've already transferred + // all of the data we need, so we can mark the data buffer as IDLE. + // + psBuffer->ui32State = BUFFER_IDLE; + + // + // If we have a callback, call it now. + // + if ( psBuffer->pfnCallback ) + { + psBuffer->pfnCallback(); + } + } + else if ( ui32Status & AM_HAL_IOM_INT_THR ) + { + // + // If we're not in the middle of a non-blocking call right now, there's + // nothing for this routine to do. + // + if ( psBuffer->ui32State == BUFFER_IDLE ) + { + return; + } + // + // If we received a threshold event in the middle of a command, we need + // to transfer data. + // + if ( psBuffer->ui32State == BUFFER_SENDING ) + { + thresh = AM_BFRn(IOMSTR, ui32Module, FIFOTHR, FIFOWTHR); + do + { + ui32SpaceInFifo = am_hal_iom_fifo_empty_slots(ui32Module); + + // + // Figure out how much data we can send. + // + if ( psBuffer->ui32BytesLeft <= ui32SpaceInFifo ) + { + // + // If the whole transfer will fit in the fifo, send it all. + // + ui32NumBytes = psBuffer->ui32BytesLeft; + } + else + { + // + // If the transfer won't fit in the fifo completely, send as + // much as we can (rounded down to a multiple of four bytes). + // + ui32NumBytes = ui32SpaceInFifo; + } + + // + // Perform the transfer. + // + am_hal_iom_fifo_write(ui32Module, psBuffer->pui32Data, ui32NumBytes); + + // Clear any spurious THR interrupt that might have got raised + // while we were adding data to FIFO + AM_BFWn(IOMSTR, ui32Module, INTCLR, THR, 1); + // + // Update the pointer and the byte counter. + // + psBuffer->ui32BytesLeft -= ui32NumBytes; + psBuffer->pui32Data += (ui32NumBytes / 4); + + if ( 0 == psBuffer->ui32BytesLeft ) + { + // + // Done with this transaction + // + break; + } + } while ( am_hal_iom_fifo_full_slots(ui32Module) <= thresh ); + } + else + { + thresh = AM_BFRn(IOMSTR, ui32Module, FIFOTHR, FIFORTHR); + while ( (ui32NumBytes = am_hal_iom_fifo_full_slots(ui32Module)) >= thresh ) + { + // + // If we get here, we're in the middle of a read. Transfer as much + // data as possible out of the FIFO and into our buffer. + // + if ( ui32NumBytes == psBuffer->ui32BytesLeft ) + { + // + // If the fifo contains our entire message, just copy the whole + // thing out. + // + am_hal_iom_fifo_read(ui32Module, psBuffer->pui32Data, + psBuffer->ui32BytesLeft); + + break; + } + else if ( ui32NumBytes >= 4 ) + { + // + // If the fifo has at least one 32-bit word in it, copy out the + // biggest block we can. + // + ui32NumBytes = (ui32NumBytes & (~0x3)); + + am_hal_iom_fifo_read(ui32Module, psBuffer->pui32Data, ui32NumBytes); + + // + // Update the pointer and the byte counter. + // + psBuffer->ui32BytesLeft -= ui32NumBytes; + psBuffer->pui32Data += (ui32NumBytes / 4); + + // Clear any spurious THR interrupt that might have got raised + // while we were reading the data from FIFO + AM_BFWn(IOMSTR, ui32Module, INTCLR, THR, 1); + } + } + } + } +} + +//***************************************************************************** +// +//! @brief Initialize the IOM queue system. +//! +//! @param ui32Module - IOM module to be initialized for queue transfers. +//! @param psQueueMemory - Memory to be used for queueing IOM transfers. +//! @param ui32QueueMemSize - Size of the queue memory. +//! +//! This function prepares the selected IOM interface for use with the IOM +//! queue system. The IOM queue system allows the caller to start multiple IOM +//! transfers in a non-blocking way. In order to do this, the HAL requires some +//! amount of memory dedicated to keeping track of IOM transactions before they +//! can be sent to the hardware registers. This function tells the HAL what +//! memory it should use for this purpose. For more information on the IOM +//! queue interface, please see the documentation for +//! am_hal_iom_queue_spi_write(). +//! +//! @note This function only needs to be called once (per module), but it must +//! be called before any other am_hal_iom_queue function. +//! +//! @note Each IOM module will need its own working space. If you intend to use +//! the queueing mechanism with more than one IOM module, you will need to +//! provide separate queue memory for each module. +//! +//! Example usage: +//! +//! @code +//! +//! // +//! // Declare an array to be used for IOM queue transactions. This array will +//! // be big enough to handle 32 IOM transactions. +//! // +//! am_hal_iom_queue_entry_t g_psQueueMemory[32]; +//! +//! // +//! // Attach the IOM0 queue system to the memory we just allocated. +//! // +//! am_hal_iom_queue_init(0, g_psQueueMemory, sizeof(g_psQueueMemory)); +//! +//! @endcode +// +//***************************************************************************** +void +am_hal_iom_queue_init(uint32_t ui32Module, am_hal_iom_queue_entry_t *psQueueMemory, + uint32_t ui32QueueMemSize) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + am_hal_queue_init(&g_psIOMQueue[ui32Module], psQueueMemory, + sizeof(am_hal_iom_queue_entry_t), ui32QueueMemSize); +} + +//***************************************************************************** +// +//! @brief Check to see how many transactions are in the queue. +//! +//! @param ui32Module Module number for the queue to check +//! +//! This function will check to see how many transactions are in the IOM queue +//! for the selected IOM module. +//! +//! @return Number of transactions in the queue. +// +//***************************************************************************** +uint32_t +am_hal_iom_queue_length_get(uint32_t ui32Module) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + return am_hal_queue_data_left(&g_psIOMQueue[ui32Module]); +} + +//***************************************************************************** +// +//! @brief Executes the next operation in the IOM queue. +//! +//! @param ui32ModuleNum - Module number for the IOM to use. +//! +//! This function checks the IOM queue to see if there are any remaining +//! transactions. If so, it will start the next available transaction in a +//! non-blocking way. +//! +//! @note This function is called automatically by am_hal_iom_queue_service(). +//! You should not call this function standalone in a normal application. +// +//***************************************************************************** +void +am_hal_iom_queue_start_next_msg(uint32_t ui32Module) +{ + am_hal_iom_queue_entry_t sIOMTransaction = {0}; + + uint32_t ui32ChipSelect; + uint32_t *pui32Data; + uint32_t ui32NumBytes; + uint32_t ui32Options; + am_hal_iom_callback_t pfnCallback; + + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Try to get the next IOM operation from the queue. + // + if ( am_hal_queue_item_get(&g_psIOMQueue[ui32Module], &sIOMTransaction, 1) ) + { + // + // Read the operation parameters + // + ui32ChipSelect = sIOMTransaction.ui32ChipSelect; + pui32Data = sIOMTransaction.pui32Data; + ui32NumBytes = sIOMTransaction.ui32NumBytes; + ui32Options = sIOMTransaction.ui32Options; + pfnCallback = sIOMTransaction.pfnCallback; + + // + // Figure out if this was a SPI or I2C write or read, and call the + // appropriate non-blocking function. + // + switch ( sIOMTransaction.ui32Operation ) + { + case AM_HAL_IOM_QUEUE_SPI_WRITE: + am_hal_iom_spi_write_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + break; + + case AM_HAL_IOM_QUEUE_SPI_READ: + am_hal_iom_spi_read_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + break; + + case AM_HAL_IOM_QUEUE_I2C_WRITE: + am_hal_iom_i2c_write_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + break; + + case AM_HAL_IOM_QUEUE_I2C_READ: + am_hal_iom_i2c_read_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + break; + } + } + + // + // Exit the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief Send a SPI frame using the IOM queue. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip-select number for this transaction. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs SPI writes to a selected SPI device. +//! +//! This function call is a queued implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. If the +//! FIFO is already in use, this function will save its arguments to the IOM +//! queue and execute the transaction when the FIFO becomes available. +//! +//! The caller will need to make sure that \e am_hal_iom_queue_service() is +//! called for IOM FIFO interrupt events and "command complete" interrupt +//! events. The \e am_hal_iom_queue_service() function will refill the FIFO as +//! necessary and call the \e pfnCallback function when the transaction is +//! finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +// +//***************************************************************************** +void +am_hal_iom_queue_spi_write(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Check to see if we need to use the queue. If the IOM is idle, and + // there's nothing in the queue already, we can go ahead and start the + // transaction in the physical IOM. Need to check for the g_bIomBusy to + // avoid a race condition where IDLE is set - but the command complete + // for previous transaction has not been processed yet + // + if ( (g_bIomBusy[ui32Module] == false) && + am_hal_queue_empty(&g_psIOMQueue[ui32Module]) ) + { + // + // Send the packet. + // + am_hal_iom_spi_write_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + } + else + { + // + // Otherwise, we'll build a transaction structure and add it to the queue. + // + am_hal_iom_queue_entry_t sIOMTransaction; + + sIOMTransaction.ui32Operation = AM_HAL_IOM_QUEUE_SPI_WRITE; + sIOMTransaction.ui32Module = ui32Module; + sIOMTransaction.ui32ChipSelect = ui32ChipSelect; + sIOMTransaction.pui32Data = pui32Data; + sIOMTransaction.ui32NumBytes = ui32NumBytes; + sIOMTransaction.ui32Options = ui32Options; + sIOMTransaction.pfnCallback = pfnCallback; + + // + // Make sure the item actually makes it into the queue + // + if ( am_hal_queue_item_add(&g_psIOMQueue[ui32Module], &sIOMTransaction, 1) == false ) + { + // + // Didn't have enough memory. + // + am_hal_debug_assert_msg(0, + "The IOM queue is full. Allocate more" + "memory to the IOM queue, or allow it more" + "time to empty between transactions."); + } + } + + // + // Exit the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief Read a SPI frame using the IOM queue. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32ChipSelect - Chip select number for this transaction. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional SPI transfer options. +//! +//! This function performs SPI reads to a selected SPI device. +//! +//! This function call is a queued implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. If the +//! FIFO is already in use, this function will save its arguments to the IOM +//! queue and execute the transaction when the FIFO becomes available. +//! +//! The caller will need to make sure that \e am_hal_iom_queue_service() is +//! called for IOM FIFO interrupt events and "command complete" interrupt +//! events. The \e am_hal_iom_queue_service() function will empty the FIFO as +//! necessary and call the \e pfnCallback function when the transaction is +//! finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +// +//***************************************************************************** +void +am_hal_iom_queue_spi_read(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Check to see if we need to use the queue. If the IOM is idle, and + // there's nothing in the queue already, we can go ahead and start the + // transaction in the physical IOM. Need to check for the g_bIomBusy to + // avoid a race condition where IDLE is set - but the command complete + // for previous transaction has not been processed yet + // + if ( (g_bIomBusy[ui32Module] == false) && + am_hal_queue_empty(&g_psIOMQueue[ui32Module]) ) + { + // + // Send the packet. + // + am_hal_iom_spi_read_nb(ui32Module, ui32ChipSelect, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + } + else + { + // + // Otherwise, we'll build a transaction structure and add it to the queue. + // + am_hal_iom_queue_entry_t sIOMTransaction; + + sIOMTransaction.ui32Operation = AM_HAL_IOM_QUEUE_SPI_READ; + sIOMTransaction.ui32Module = ui32Module; + sIOMTransaction.ui32ChipSelect = ui32ChipSelect; + sIOMTransaction.pui32Data = pui32Data; + sIOMTransaction.ui32NumBytes = ui32NumBytes; + sIOMTransaction.ui32Options = ui32Options; + sIOMTransaction.pfnCallback = pfnCallback; + + // + // Make sure the item actually makes it into the queue + // + if ( am_hal_queue_item_add(&g_psIOMQueue[ui32Module], &sIOMTransaction, 1) == false ) + { + // + // Didn't have enough memory. + // + am_hal_debug_assert_msg(0, + "The IOM queue is full. Allocate more" + "memory to the IOM queue, or allow it more" + "time to empty between transactions."); + } + } + + // + // Exit the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief Send an I2C frame using the IOM queue. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32BusAddress - I2C address of the target device. +//! @param pui32Data - Pointer to the bytes that will be sent. +//! @param ui32NumBytes - Number of bytes to send. +//! @param ui32Options - Additional I2C transfer options. +//! +//! This function performs I2C writes to a selected I2C device. +//! +//! This function call is a queued implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. If the +//! FIFO is already in use, this function will save its arguments to the IOM +//! queue and execute the transaction when the FIFO becomes available. +//! +//! The caller will need to make sure that \e am_hal_iom_queue_service() is +//! called for IOM FIFO interrupt events and "command complete" interrupt +//! events. The \e am_hal_iom_queue_service() function will refill the FIFO as +//! necessary and call the \e pfnCallback function when the transaction is +//! finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +// +//***************************************************************************** +void +am_hal_iom_queue_i2c_write(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Check to see if we need to use the queue. If the IOM is idle, and + // there's nothing in the queue already, we can go ahead and start the + // transaction in the physical IOM. Need to check for the g_bIomBusy to + // avoid a race condition where IDLE is set - but the command complete + // for previous transaction has not been processed yet + // + if ( (g_bIomBusy[ui32Module] == false) && + am_hal_queue_empty(&g_psIOMQueue[ui32Module]) ) + { + // + // Send the packet. + // + am_hal_iom_i2c_write_nb(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + } + else + { + // + // Otherwise, we'll build a transaction structure and add it to the queue. + // + am_hal_iom_queue_entry_t sIOMTransaction; + + sIOMTransaction.ui32Operation = AM_HAL_IOM_QUEUE_I2C_WRITE; + sIOMTransaction.ui32Module = ui32Module; + sIOMTransaction.ui32ChipSelect = ui32BusAddress; + sIOMTransaction.pui32Data = pui32Data; + sIOMTransaction.ui32NumBytes = ui32NumBytes; + sIOMTransaction.ui32Options = ui32Options; + sIOMTransaction.pfnCallback = pfnCallback; + + // + // Make sure the item actually makes it into the queue + // + if ( am_hal_queue_item_add(&g_psIOMQueue[ui32Module], &sIOMTransaction, 1) == false ) + { + // + // Didn't have enough memory. + // + am_hal_debug_assert_msg(0, + "The IOM queue is full. Allocate more" + "memory to the IOM queue, or allow it more" + "time to empty between transactions."); + } + } + + // + // Exit the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief Read a I2C frame using the IOM queue. +//! +//! @param ui32Module - Module number for the IOM +//! @param ui32BusAddress - I2C address of the target device. +//! @param pui32Data - Pointer to the array where received bytes should go. +//! @param ui32NumBytes - Number of bytes to read. +//! @param ui32Options - Additional I2C transfer options. +//! +//! This function performs I2C reads to a selected I2C device. +//! +//! This function call is a queued implementation. It will write as much +//! data to the FIFO as possible immediately, store a pointer to the remaining +//! data, start the transfer on the bus, and then immediately return. If the +//! FIFO is already in use, this function will save its arguments to the IOM +//! queue and execute the transaction when the FIFO becomes available. +//! +//! The caller will need to make sure that \e am_hal_iom_queue_service() is +//! called for IOM FIFO interrupt events and "command complete" interrupt +//! events. The \e am_hal_iom_queue_service() function will empty the FIFO as +//! necessary and call the \e pfnCallback function when the transaction is +//! finished. +//! +//! @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words. +//! This means that you will need to byte-pack the \e pui32Data array with the +//! data you intend to send over the interface. One easy way to do this is to +//! declare the array as a 32-bit integer array, but use an 8-bit pointer to +//! put your actual data into the array. If there are not enough bytes in your +//! desired message to completely fill the last 32-bit word, you may pad that +//! last word with bytes of any value. The IOM hardware will only read the +//! first \e ui32NumBytes in the \e pui8Data array. +// +//***************************************************************************** +void +am_hal_iom_queue_i2c_read(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, am_hal_iom_callback_t pfnCallback) +{ + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + am_hal_debug_assert_msg(ui32NumBytes > 0, + "Trying to do a 0 byte transaction"); + + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Check to see if we need to use the queue. If the IOM is idle, and + // there's nothing in the queue already, we can go ahead and start the + // transaction in the physical IOM. Need to check for the g_bIomBusy to + // avoid a race condition where IDLE is set - but the command complete + // for previous transaction has not been processed yet + // + if ( (g_bIomBusy[ui32Module] == false) && + am_hal_queue_empty(&g_psIOMQueue[ui32Module]) ) + { + // + // Send the packet. + // + am_hal_iom_i2c_read_nb(ui32Module, ui32BusAddress, pui32Data, + ui32NumBytes, ui32Options, pfnCallback); + } + else + { + // + // Otherwise, we'll build a transaction structure and add it to the queue. + // + am_hal_iom_queue_entry_t sIOMTransaction; + + sIOMTransaction.ui32Operation = AM_HAL_IOM_QUEUE_I2C_READ; + sIOMTransaction.ui32Module = ui32Module; + sIOMTransaction.ui32ChipSelect = ui32BusAddress; + sIOMTransaction.pui32Data = pui32Data; + sIOMTransaction.ui32NumBytes = ui32NumBytes; + sIOMTransaction.ui32Options = ui32Options; + sIOMTransaction.pfnCallback = pfnCallback; + + // + // Make sure the item actually makes it into the queue + // + if ( am_hal_queue_item_add(&g_psIOMQueue[ui32Module], &sIOMTransaction, 1) == false ) + { + // + // Didn't have enough memory. + // + am_hal_debug_assert_msg(0, "The IOM queue is full. Allocate more" + "memory to the IOM queue, or allow it more" + "time to empty between transactions."); + } + } + + // + // Exit the critical section. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief "Block" until the queue of IOM transactions is over. +//! +//! @param ui32Module - Module number for the IOM. +//! +//! This function will sleep the core block until the queue for the selected +//! IOM is empty. This is mainly useful for non-RTOS applications where the +//! caller needs to know that a certain IOM transaction is complete before +//! continuing with the main program flow. +//! +//! @note This function will put the core to sleep while it waits for the +//! queued IOM transactions to complete. This will save power, in most +//! situations, but it may not be the best option in all cases. \e Do \e not +//! call this function from interrupt context (the core may not wake up again). +//! \e Be \e careful using this function from an RTOS task (many RTOS +//! implementations use hardware interrupts to switch contexts, and most RTOS +//! implementations expect to control sleep behavior). +// +//***************************************************************************** +void +am_hal_iom_sleeping_queue_flush(uint32_t ui32Module) +{ + bool bWaiting = true; + uint32_t ui32Critical; + + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Loop forever waiting for the IOM to be idle and the queue to be empty. + // + while ( bWaiting ) + { + // + // Start a critical section. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // Check the queue and the IOM itself. + // + if ( (g_bIomBusy[ui32Module] == false) && + am_hal_queue_empty(&g_psIOMQueue[ui32Module]) ) + { + // + // If the queue is empty and the IOM is idle, we can go ahead and + // return. + // + bWaiting = false; + } + else + { + // + // Otherwise, we should sleep until the interface is actually free. + // + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_NORMAL); + } + + // + // End the critical section. + // + am_hal_interrupt_master_set(ui32Critical); + } +} + +//***************************************************************************** +// +//! @brief Service IOM transaction queue. +//! +//! @param ui32Module - Module number for the IOM to be used. +//! @param ui32Status - Interrupt status bits for the IOM module being used. +//! +//! This function handles the operation of FIFOs and the IOM queue during +//! queued IOM transactions. If you are using \e am_hal_iom_queue_spi_write() +//! or similar functions, you will need to call this function in your interrupt +//! handler. +//! +//! @note This interrupt service routine relies on the user to enable the IOM +//! interrupts for FIFO threshold and CMD complete. +//! +//! Example: +//! +//! @code +//! void +//! am_iomaster0_isr(void) +//! { +//! uint32_t ui32Status; +//! +//! // +//! // Check to see which interrupt caused us to enter the ISR. +//! // +//! ui32Status = am_hal_iom_int_status(0, true); +//! +//! // +//! // Fill or empty the FIFO, and either continue the current operation or +//! // start the next one in the queue. If there was a callback, it will be +//! // called here. +//! // +//! am_hal_iom_queue_service(0, ui32Status); +//! +//! // +//! // Clear the interrupts before leaving the ISR. +//! // +//! am_hal_iom_int_clear(ui32Status); +//! } +//! @endcode +//! +//! @return +// +//***************************************************************************** +void +am_hal_iom_queue_service(uint32_t ui32Module, uint32_t ui32Status) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + // + // Service the FIFOs in case this was a threshold interrupt. + // + am_hal_iom_int_service(ui32Module, ui32Status); + + // + // If the last interrupt was a "command complete", then the IOM should be + // idle already or very soon. Make absolutely sure that the IOM is not in + // use, and then start the next transaction in the queue. + // + if ( ui32Status & AM_HAL_IOM_INT_CMDCMP ) + { + if ( g_psIOMQueue[ui32Module].pui8Data != NULL ) + { + am_hal_iom_queue_start_next_msg(ui32Module); + } + } +} + +//***************************************************************************** +// +//! @brief Enable selected IOM Interrupts. +//! +//! @param ui32Module - Module number. +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_iom.h +//! +//! Use this function to enable the IOM interrupts. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_iom_int_enable(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + AM_REGn(IOMSTR, ui32Module, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return the enabled IOM Interrupts. +//! +//! @param ui32Module - Module number. +//! +//! Use this function to return all enabled IOM interrupts. +//! +//! @return all enabled IOM interrupts. +// +//***************************************************************************** +uint32_t +am_hal_iom_int_enable_get(uint32_t ui32Module) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + return AM_REGn(IOMSTR, ui32Module, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable selected IOM Interrupts. +//! +//! @param ui32Module - Module number. +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_iom.h +//! +//! Use this function to disable the IOM interrupts. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_iom_int_disable(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + AM_REGn(IOMSTR, ui32Module, INTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Clear selected IOM Interrupts. +//! +//! @param ui32Module - Module number. +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_iom.h +//! +//! Use this function to clear the IOM interrupts. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_iom_int_clear(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + AM_REGn(IOMSTR, ui32Module, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Set selected IOM Interrupts. +//! +//! @param ui32Module - Module number. +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_iom.h +//! +//! Use this function to set the IOM interrupts. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_iom_int_set(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return; + } + + AM_REGn(IOMSTR, ui32Module, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return the IOM Interrupt status. +//! +//! @param ui32Module - Module number. +//! @param bEnabledOnly - return only the enabled interrupts. +//! +//! Use this function to get the IOM interrupt status. +//! +//! @return interrupt status +// +//***************************************************************************** +uint32_t +am_hal_iom_int_status_get(uint32_t ui32Module, bool bEnabledOnly) +{ + // + // Validate parameters + // + if ( ui32Module >= AM_REG_IOMSTR_NUM_MODULES ) + { + return 0; + } + + if ( bEnabledOnly ) + { + uint32_t u32RetVal = AM_REGn(IOMSTR, ui32Module, INTSTAT); + return u32RetVal & AM_REGn(IOMSTR, ui32Module, INTEN); + } + else + { + return AM_REGn(IOMSTR, ui32Module, INTSTAT); + } +} + + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_iom.h b/bsp/apollo2/libraries/drivers/hal/am_hal_iom.h new file mode 100644 index 0000000000..e5a450f15c --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_iom.h @@ -0,0 +1,559 @@ +//***************************************************************************** +// +// am_hal_iom.h +//! @file +//! +//! @brief Functions for accessing and configuring the IO Master module +//! +//! @addtogroup iom2 IO Master (SPI/I2C) +//! @ingroup apollo2hal +//! @{ + +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_IOM_H +#define AM_HAL_IOM_H + +//***************************************************************************** +// +// Macro definitions +// +//***************************************************************************** + +//***************************************************************************** +// +//! @name IOM Clock Frequencies +//! @brief Macro definitions for common SPI and I2C clock frequencies. +//! +//! These macros may be used with the ui32ClockFrequency member of the +//! am_hal_iom_config_t structure to set the clock frequency of the serial +//! interfaces. +//! +//! This list of frequencies is not exhaustive by any means. If your desired +//! frequency is not in this list, simply set ui32ClockFrequency to the +//! desired frequency (in Hz) when calling am_hal_iom_config(). +// +//***************************************************************************** +#define AM_HAL_IOM_24MHZ 24000000 +#define AM_HAL_IOM_16MHZ 16000000 +#define AM_HAL_IOM_12MHZ 12000000 +#define AM_HAL_IOM_8MHZ 8000000 +#define AM_HAL_IOM_6MHZ 6000000 +#define AM_HAL_IOM_4MHZ 4000000 +#define AM_HAL_IOM_3MHZ 3000000 +#define AM_HAL_IOM_2MHZ 2000000 +#define AM_HAL_IOM_1_5MHZ 1500000 +#define AM_HAL_IOM_1MHZ 1000000 +#define AM_HAL_IOM_750KHZ 750000 +#define AM_HAL_IOM_500KHZ 500000 +#define AM_HAL_IOM_400KHZ 400000 +#define AM_HAL_IOM_375KHZ 375000 +#define AM_HAL_IOM_250KHZ 250000 +#define AM_HAL_IOM_125KHZ 125000 +#define AM_HAL_IOM_100KHZ 100000 +#define AM_HAL_IOM_50KHZ 50000 +#define AM_HAL_IOM_10KHZ 10000 + +// Hardware FIFO Size +#define AM_HAL_IOM_MAX_FIFO_SIZE 128 + +//***************************************************************************** +// +//! @name IOM Physical Protocols +//! @brief Macro Definitions for general IOM configuration. +//! +//! These macros may be used with the am_hal_iom_config_t structure to set the +//! operating parameters of each serial IO master module. Choose SPIMODE to +//! select the SPI interface, or I2CMODE to select the I2C interface. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_SPIMODE AM_REG_IOMSTR_CFG_IFCSEL(1) +#define AM_HAL_IOM_I2CMODE AM_REG_IOMSTR_CFG_IFCSEL(0) +//! @} + +//***************************************************************************** +// +//! @name IOM Operations +//! @brief Macro definitions used for ui32Operation parameters. +//! +//! These macros may be used to specify which action an IOM command will +//! execute. The 'OFFSET' operations will cause the IOM hardware to transmit the +//! provided 1-byte 'offset' before executing the rest of the command. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_WRITE 0x00000000 +#define AM_HAL_IOM_READ 0x80000000 +//! @} + +//***************************************************************************** +// +//! @name Command Options +//! @brief Macro definitions used for ui32Options parameters. +//! +//! These macros are all related to SPI or I2C command words. They can be used +//! to set specific options on a per-transaction basis. +//! +//! - CS_LOW - Do not raise the CS signal at the end of this SPI command. +//! - NO_STOP - Do not release the I2C bus with a STOP bit after this command. +//! - LSB_FIRST - Reverse the payload bits of this command. +//! - 10BIT_ADDRESS - (I2C only) use a 10-bit I2C address protocol. +//! - RAW - Don't use an offset byte. +//! - OFFSET() - Send this 1-byte offset as the first byte of the transaction. +//! This can be used to access "registers" in external I2C devices, or add a +//! 1-byte write to the beginning of a SPI write or read command. See +//! "normal mode" operation in the I2C/SPI Master section of the datasheet +//! for more information on this parameter. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_CS_LOW 0x10000000 +#define AM_HAL_IOM_NO_STOP 0x10000000 +#define AM_HAL_IOM_LSB_FIRST 0x08000000 +#define AM_HAL_IOM_10BIT_ADDRESS 0x04000000 +#define AM_HAL_IOM_RAW 0x40000000 +#define AM_HAL_IOM_OFFSET(n) (((n) << 8) & 0x0000FF00) +//! @} + +//***************************************************************************** +// +//! @name IOM Interrupts +//! @brief Macro definitions for IOM interrupt status bits. +//! +//! These macros correspond to the bits in the IOM interrupt status register. +//! They may be used with any of the \e am_hal_iom_int_x() functions. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_INT_ARB AM_REG_IOMSTR_INTEN_ARB_M +#define AM_HAL_IOM_INT_STOP AM_REG_IOMSTR_INTEN_STOP_M +#define AM_HAL_IOM_INT_START AM_REG_IOMSTR_INTEN_START_M +#define AM_HAL_IOM_INT_ICMD AM_REG_IOMSTR_INTEN_ICMD_M +#define AM_HAL_IOM_INT_IACC AM_REG_IOMSTR_INTEN_IACC_M +#define AM_HAL_IOM_INT_WTLEN AM_REG_IOMSTR_INTEN_WTLEN_M +#define AM_HAL_IOM_INT_NAK AM_REG_IOMSTR_INTEN_NAK_M +#define AM_HAL_IOM_INT_FOVFL AM_REG_IOMSTR_INTEN_FOVFL_M +#define AM_HAL_IOM_INT_FUNDFL AM_REG_IOMSTR_INTEN_FUNDFL_M +#define AM_HAL_IOM_INT_THR AM_REG_IOMSTR_INTEN_THR_M +#define AM_HAL_IOM_INT_CMDCMP AM_REG_IOMSTR_INTEN_CMDCMP_M +//! @} + +//***************************************************************************** +// +//! @name IOM function errors +//! @brief Return values for IOM HAL function errors, such as with the function +//! am_hal_iom_error_status_get(). +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_ERR_INVALID_MODULE (1 << 30) +//! @} + +//***************************************************************************** +// +//! @name Software IOM modules +//! @brief Macro definitions for using the software I2C interface. +//! +//! Use this macro as the module number for standard IOM functions to emulate +//! them using the bit-banged i2c interface. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOM_I2CBB_MODULE AM_REG_IOMSTR_NUM_MODULES +//! @} + +//***************************************************************************** +// +//! @brief Union type for a word-aligned, byte-addressable array. +//! +//! This is a convenience macro that may be used to define byte-addressable +//! arrays with 32-bit alignment. This allows the programmer to define SPI or +//! I2C transactions as a series of 8-bit values, but also write them to the +//! IOM FIFO efficiently as a series of 32-bit values. +//! +//! Example usage: +//! +//! @code +//! // +//! // Declare a buffer array with at least 3-bytes worth of space. +//! // +//! am_hal_iom_buffer(3) sBuffer; +//! +//! // +//! // Populate the buffer with a 3-byte command. +//! // +//! sBuffer.bytes[0] = 's'; +//! sBuffer.bytes[1] = 'p'; +//! sBuffer.bytes[2] = 'i'; +//! +//! // +//! // Send the buffer over the spi interface. +//! // +//! am_hal_iom_spi_write(psDevice, sBuffer.words, 3, 0); +//! +//! @endcode +// +//***************************************************************************** +#define am_hal_iom_buffer(A) \ + union \ + { \ + uint32_t words[(A + 3) >> 2]; \ + uint8_t bytes[A]; \ + } + +//***************************************************************************** +// +//! @brief Configuration structure for the IO master module. +// +//***************************************************************************** +typedef struct +{ + // + //! @brief Selects the physical protocol for the IO master module. Choose + //! either AM_HAL_IOM_SPIMODE or AM_HAL_IOM_I2CMODE. + // + uint32_t ui32InterfaceMode; + + // + //! @brief Selects the output clock frequency for SPI or I2C mode. Choose + //! one of the AM_HAL_IOM_nMHZ or AM_HAL_IOM_nKHZ macros. + // + uint32_t ui32ClockFrequency; + + // + //! Select the SPI clock phase (unused in I2C mode). + // + bool bSPHA; + + // + //! Select the SPI clock polarity (unused in I2C mode). + // + bool bSPOL; + + // + //! @brief Select the FIFO write threshold. + //! + //! The IOM controller will generate a processor interrupt when the number + //! of entries in the FIFO goes *below* this number. + // + uint8_t ui8WriteThreshold; + + // + //! @brief Select the FIFO read threshold. + //! + //! The IOM controller will generate a processor interrupt when the number + //! of entries in the FIFO grows *larger* than this number. + // + uint8_t ui8ReadThreshold; + +} +am_hal_iom_config_t; + +//***************************************************************************** +// +//! Configuration structure for an individual SPI device. +// +//***************************************************************************** +typedef struct +{ + // + //! IOM module to use for communicating with this device. + // + uint32_t ui32Module; + + // + //! Chip select signal that should be used for this device. + // + uint32_t ui32ChipSelect; + + // + //! Additional options that will ALWAYS be ORed into the command word. + // + uint32_t ui32Options; +} +am_hal_iom_spi_device_t; + +//***************************************************************************** +// +//! Configuration structure for an individual I2C device. +// +//***************************************************************************** +typedef struct +{ + // + //! IOM module to use for communicating with this device. + // + uint32_t ui32Module; + + // + //! I2C address associated with this device. + // + uint32_t ui32BusAddress; + + // + //! Additional options that will ALWAYS be ORed into the command word. + // + uint32_t ui32Options; +} +am_hal_iom_i2c_device_t; + +//***************************************************************************** +// +// Typedef for non-blocking function callbacks. +// +//***************************************************************************** +typedef void (*am_hal_iom_callback_t)(void); + +//***************************************************************************** +// +// Typedef for a function that waits until the IOM queue is empty. +// +//***************************************************************************** +typedef void (*am_hal_iom_queue_flush_t)(uint32_t); + +extern am_hal_iom_queue_flush_t am_hal_iom_queue_flush; + + +//***************************************************************************** +// +// Operations +// +//***************************************************************************** +#define AM_HAL_IOM_QUEUE_SPI_WRITE 0 +#define AM_HAL_IOM_QUEUE_SPI_READ 1 +#define AM_HAL_IOM_QUEUE_I2C_WRITE 2 +#define AM_HAL_IOM_QUEUE_I2C_READ 3 + +//***************************************************************************** +// +// Structure to hold IOM operations. +// +//***************************************************************************** +typedef struct +{ + uint32_t ui32Operation; + uint32_t ui32Module; + uint32_t ui32ChipSelect; + uint32_t *pui32Data; + uint32_t ui32NumBytes; + uint32_t ui32Options; + am_hal_iom_callback_t pfnCallback; +} +am_hal_iom_queue_entry_t; + +//***************************************************************************** +// +// Structure to hold IOM configuration during module power-down. +// +//***************************************************************************** +typedef struct +{ + uint32_t FIFOTHR; + uint32_t CLKCFG; + uint32_t CFG; + uint32_t INTEN; + uint32_t bValid; +} +am_hal_iom_pwrsave_t; + +//***************************************************************************** +// +// Global variables +// +//***************************************************************************** +extern am_hal_iom_pwrsave_t am_hal_iom_pwrsave[AM_REG_IOMSTR_NUM_MODULES]; +extern uint32_t g_iom_error_status; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_iom_pwrctrl_enable(uint32_t ui32Module); +extern void am_hal_iom_pwrctrl_disable(uint32_t ui32Module); +extern void am_hal_iom_power_on_restore(uint32_t ui32Module); +extern void am_hal_iom_power_off_save(uint32_t ui32Module); +extern void am_hal_iom_config(uint32_t ui32Module, + const am_hal_iom_config_t *psConfig); +extern uint32_t am_hal_iom_frequency_get(uint32_t ui32Module); +extern void am_hal_iom_enable(uint32_t ui32Module); +extern void am_hal_iom_disable(uint32_t ui32Module); +extern void am_hal_iom_spi_write(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_spi_read(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options); +extern uint32_t am_hal_iom_spi_write_nq(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options); +extern uint32_t am_hal_iom_spi_read_nq(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_spi_write_nb(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern uint32_t am_hal_iom_spi_read_nb(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_spi_cmd_run(uint32_t ui32Operation, + uint32_t ui32Module, + uint32_t ui32ChipSelect, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_i2c_write(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_i2c_read(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern uint32_t am_hal_iom_i2c_write_nq(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern uint32_t am_hal_iom_i2c_read_nq(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_i2c_write_nb(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_i2c_read_nb(uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t *pui32Data, + uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_i2c_cmd_run(uint32_t ui32Operation, + uint32_t ui32Module, + uint32_t ui32BusAddress, + uint32_t ui32NumBytes, + uint32_t ui32Options); +extern void am_hal_iom_command_repeat_set(uint32_t ui32Module, + uint32_t ui32CmdCount); +extern uint32_t am_hal_iom_status_get(uint32_t ui32Module); +extern uint32_t am_hal_iom_error_status_get(uint32_t ui32Module); +extern uint32_t am_hal_iom_fifo_write(uint32_t ui32Module, uint32_t *pui32Data, + uint32_t ui32NumBytes); +extern uint32_t am_hal_iom_fifo_read(uint32_t ui32Module, uint32_t *pui32Data, + uint32_t ui32NumBytes); +extern uint8_t am_hal_iom_fifo_empty_slots(uint32_t ui32Module); +extern uint8_t am_hal_iom_fifo_full_slots(uint32_t ui32Module); +extern void am_hal_iom_poll_complete(uint32_t ui32Module); +extern void am_hal_iom_int_service(uint32_t ui32Module, uint32_t ui32Status); +extern void am_hal_iom_int_enable(uint32_t ui32Module, uint32_t ui32Interrupt); +extern uint32_t am_hal_iom_int_enable_get(uint32_t ui32Module); +extern void am_hal_iom_int_disable(uint32_t ui32Module, uint32_t ui32Interrupt); +extern void am_hal_iom_int_clear(uint32_t ui32Module, uint32_t ui32Interrupt); +extern void am_hal_iom_int_set(uint32_t ui32Module, uint32_t ui32Interrupt); +extern uint32_t am_hal_iom_int_status_get(uint32_t ui32Module, bool bEnabledOnly); +extern void am_hal_iom_queue_init(uint32_t ui32ModuleNum, + am_hal_iom_queue_entry_t *psQueueMemory, + uint32_t ui32QueueMemSize); +extern uint32_t am_hal_iom_queue_length_get(uint32_t ui32Module); +extern void am_hal_iom_sleeping_queue_flush(uint32_t ui32Module); +extern void am_hal_iom_queue_spi_write(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_queue_spi_read(uint32_t ui32Module, uint32_t ui32ChipSelect, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_queue_i2c_write(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_queue_i2c_read(uint32_t ui32Module, uint32_t ui32BusAddress, + uint32_t *pui32Data, uint32_t ui32NumBytes, + uint32_t ui32Options, + am_hal_iom_callback_t pfnCallback); +extern void am_hal_iom_queue_start_next_msg(uint32_t ui32Module); +extern void am_hal_iom_queue_service(uint32_t ui32Module, uint32_t ui32Status); + +//***************************************************************************** +// +// Helper functions. +// +//***************************************************************************** +#define AM_IOMASTER_ISR_QUEUE(x) \ +void am_iomaster##x##_isr(void) \ +{ \ + uint32_t ui32IntStatus; \ + g_iom_error_status = am_hal_iom_error_status_get(x); \ + ui32IntStatus = am_hal_iom_int_status_get(x, false); \ + am_hal_iom_int_clear(x, ui32IntStatus); \ + am_hal_iom_queue_service(x, ui32IntStatus); \ +} + +#define AM_IOMASTER_ISR_NB(x) \ +void am_iomaster##x##_isr(void) \ +{ \ + uint32_t ui32IntStatus; \ + g_iom_error_status = am_hal_iom_error_status_get(x); \ + ui32IntStatus = am_hal_iom_int_status_get(x, false); \ + am_hal_iom_int_clear(x, ui32IntStatus); \ + am_hal_iom_int_service(x, ui32IntStatus); \ +} + +#endif // AM_HAL_IOM_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_ios.c b/bsp/apollo2/libraries/drivers/hal/am_hal_ios.c new file mode 100644 index 0000000000..0f34aa6efb --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_ios.c @@ -0,0 +1,1303 @@ +//***************************************************************************** +// +// am_hal_ios.c +//! @file +//! +//! @brief Functions for interfacing with the IO Slave module +//! +//! @addtogroup ios2 IO Slave (SPI/I2C) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// SRAM Buffer structure +// +//***************************************************************************** +typedef struct +{ + uint8_t *pui8Data; + volatile uint32_t ui32WriteIndex; + volatile uint32_t ui32ReadIndex; + volatile uint32_t ui32Length; + uint32_t ui32Capacity; +} +am_hal_ios_buffer_t; + +am_hal_ios_buffer_t g_sSRAMBuffer; + +//***************************************************************************** +// +// Forward declarations of static funcitons. +// +//***************************************************************************** +static void am_hal_ios_buffer_init(am_hal_ios_buffer_t *psBuffer, + void *pvArray, uint32_t ui32Bytes); + +static void fifo_write(uint8_t *pui8Data, uint32_t ui32NumBytes); + +//***************************************************************************** +// +// Function-like macros. +// +//***************************************************************************** +#define am_hal_ios_buffer_empty(psBuffer) \ + ((psBuffer)->ui32Length == 0) + +#define am_hal_ios_buffer_full(psBuffer) \ + ((psBuffer)->ui32Length == (psBuffer)->ui32Capacity) + +#define am_hal_ios_buffer_data_left(psBuffer) \ + ((psBuffer)->ui32Length) + +//***************************************************************************** +// +// Global Variables +// +//***************************************************************************** +volatile uint8_t * const am_hal_ios_pui8LRAM = (uint8_t *)REG_IOSLAVE_BASEADDR; +uint8_t *g_pui8FIFOBase = (uint8_t *) REG_IOSLAVE_BASEADDR; +uint8_t *g_pui8FIFOEnd = (uint8_t *) REG_IOSLAVE_BASEADDR; +uint8_t *g_pui8FIFOPtr = (uint8_t *) REG_IOSLAVE_BASEADDR; +uint8_t g_ui32HwFifoSize = 0; +uint32_t g_ui32FifoBaseOffset = 0; + +//***************************************************************************** +// +//! @brief Enable the IOS in the power control block. +//! +//! This function enables the IOS module in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_pwrctrl_enable(void) +{ + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_IOS); +} + +//***************************************************************************** +// +//! @brief Disable the IOS in the power control block. +//! +//! This function disables the IOS module in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_pwrctrl_disable(void) +{ + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_IOS); +} + +//***************************************************************************** +// +//! @brief Enables the IOS module +//! +//! This function enables the IOSLAVE module using the IFCEN bitfield in the +//! IOSLAVE_CFG register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_enable(uint32_t ui32Module) +{ + AM_REGn(IOSLAVE, ui32Module, CFG) |= AM_REG_IOSLAVE_CFG_IFCEN(1); +} + +//***************************************************************************** +// +//! @brief Disables the IOSLAVE module. +//! +//! This function disables the IOSLAVE module using the IFCEN bitfield in the +//! IOSLAVE_CFG register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_disable(uint32_t ui32Module) +{ + AM_REGn(IOSLAVE, ui32Module, CFG) &= ~(AM_REG_IOSLAVE_CFG_IFCEN(1)); +} + +//***************************************************************************** +// +//! @brief Configure the IOS module. +//! +//! This function reads the an \e am_hal_ios_config_t structure and uses it to +//! set up the IO Slave module. Please see the information on the configuration +//! structure for more information on the parameters that may be set by this +//! function. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_config(am_hal_ios_config_t *psConfig) +{ + uint32_t ui32LRAMConfig; + + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_IOS); + + // + // Record the FIFO parameters for later use. + // + g_pui8FIFOBase = (uint8_t *)(REG_IOSLAVE_BASEADDR + psConfig->ui32FIFOBase); + g_pui8FIFOEnd = (uint8_t *)(REG_IOSLAVE_BASEADDR + psConfig->ui32RAMBase); + g_ui32HwFifoSize = g_pui8FIFOEnd - g_pui8FIFOBase; + g_ui32FifoBaseOffset = psConfig->ui32FIFOBase; + + // + // Caluclate the value for the IO Slave FIFO configuration register. + // + ui32LRAMConfig = AM_REG_IOSLAVE_FIFOCFG_ROBASE(psConfig->ui32ROBase >> 3); + ui32LRAMConfig |= AM_REG_IOSLAVE_FIFOCFG_FIFOBASE(psConfig->ui32FIFOBase >> 3); + ui32LRAMConfig |= AM_REG_IOSLAVE_FIFOCFG_FIFOMAX(psConfig->ui32RAMBase >> 3); + + // + // Just in case, disable the IOS + // + am_hal_ios_disable(0); + + // + // Write the configuration register with the user's selected interface + // characteristics. + // + AM_REG(IOSLAVE, CFG) = psConfig->ui32InterfaceSelect; + + // + // Write the FIFO configuration register to set the memory map for the LRAM. + // + AM_REG(IOSLAVE, FIFOCFG) = ui32LRAMConfig; + + // + // Enable the IOS. The following configuration options can't be set while + // the IOS is disabled. + // + am_hal_ios_enable(0); + + // + // Initialize the FIFO pointer to the beginning of the FIFO section. + // + am_hal_ios_fifo_ptr_set(psConfig->ui32FIFOBase); + + // + // Write the FIFO threshold register. + // + AM_REG(IOSLAVE, FIFOTHR) = psConfig->ui32FIFOThreshold; +} + +//***************************************************************************** +// +//! @brief Set bits in the HOST side IOINTCTL register. +//! +//! This function may be used to set an interrupt bit to the host. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_host_int_set(uint32_t ui32Interrupt) +{ + // + // Set a bit that will cause an interrupt to the host. + // + AM_REG(IOSLAVE, IOINTCTL) = AM_REG_IOSLAVE_IOINTCTL_IOINTSET(ui32Interrupt); +} + +//***************************************************************************** +// +//! @brief Clear bits in the HOST side IOINTCTL register. +//! +//! This function may be used to clear an interrupt bit to the host. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_host_int_clear(uint32_t ui32Interrupt) +{ + // + // Clear bits that will cause an interrupt to the host. + // + AM_REG(IOSLAVE, IOINTCTL) = AM_REG_IOSLAVE_IOINTCTL_IOINTCLR(ui32Interrupt); +} + +//***************************************************************************** +// +//! @brief Get the bits in the HOST side IOINTCTL register. +//! +//! This function may be used to read the host side interrupt bits. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_ios_host_int_get(void) +{ + // + // return the value of the bits that will cause an interrupt to the host. + // + return AM_BFR(IOSLAVE, IOINTCTL, IOINT); +} + +//***************************************************************************** +// +//! @brief Get the enable bits in the HOST side IOINTCTL register. +//! +//! This function may be used to read the host side interrupt bits. +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_ios_host_int_enable_get(void) +{ + // + // return the value of the bits that will cause an interrupt to the host. + // + return AM_BFR(IOSLAVE, IOINTCTL, IOINTEN); +} + +//***************************************************************************** +// +//! @brief Enable an IOS Access Interrupt. +//! +//! This function may be used to enable an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_access_int_enable(uint32_t ui32Interrupt) +{ + // + // OR the desired interrupt into the enable register. + // + AM_REG(IOSLAVE, REGACCINTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return all enabled IOS Access Interrupts. +//! +//! This function may be used to return all enabled IOS Access interrupts. +//! +//! @return the enabled interrrupts. +// +//***************************************************************************** +uint32_t +am_hal_ios_access_int_enable_get(void) +{ + // + // Return the enabled interrupts. + // + return AM_REG(IOSLAVE, REGACCINTEN); +} + +//***************************************************************************** +// +//! @brief Disable an IOS Access Interrupt. +//! +//! This function may be used to disable an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_access_int_disable(uint32_t ui32Interrupt) +{ + // + // Clear the desired bit from the interrupt enable register. + // + AM_REG(IOSLAVE, REGACCINTEN) &= ~(ui32Interrupt); +} + +//***************************************************************************** +// +//! @brief Clear an IOS Access Interrupt. +//! +//! This function may be used to clear an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_access_int_clear(uint32_t ui32Interrupt) +{ + // + // Use the interrupt clear register to deactivate the chosen interrupt. + // + AM_REG(IOSLAVE, REGACCINTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Set an IOS Access Interrupt. +//! +//! This function may be used to set an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_access_int_set(uint32_t ui32Interrupt) +{ + // + // Use the interrupt set register to activate the chosen interrupt. + // + AM_REG(IOSLAVE, REGACCINTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Check the status of an IOS Access Interrupt. +//! +//! @param bEnabledOnly - return only the enabled interrupt status. +//! +//! This function may be used to return the enabled interrupt status. +//! +//! @return the enabled interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_ios_access_int_status_get(bool bEnabledOnly) +{ + if ( bEnabledOnly ) + { + uint32_t u32RetVal = AM_REG(IOSLAVE, REGACCINTSTAT); + return u32RetVal & AM_REG(IOSLAVE, REGACCINTEN); + + } + else + { + return AM_REG(IOSLAVE, REGACCINTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Enable an IOS Interrupt. +//! +//! @param ui32Interrupt - desired interrupts. +//! +//! This function may be used to enable an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_int_enable(uint32_t ui32Interrupt) +{ + // + // OR the desired interrupt into the enable register. + // + AM_REG(IOSLAVE, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return all enabled IOS Interrupts. +//! +//! This function may be used to return all enabled IOS interrupts. +//! +//! @return the enabled interrrupts. +// +//***************************************************************************** +uint32_t +am_hal_ios_int_enable_get(void) +{ + // + // Return the enabled interrupts. + // + return AM_REG(IOSLAVE, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable an IOS Interrupt. +//! +//! @param ui32Interrupt - desired interrupts. +//! +//! This function may be used to disable an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_int_disable(uint32_t ui32Interrupt) +{ + // + // Clear the desired bit from the interrupt enable register. + // + AM_REG(IOSLAVE, INTEN) &= ~(ui32Interrupt); +} + +//***************************************************************************** +// +//! @brief Clear an IOS Interrupt. +//! +//! @param ui32Interrupt - desired interrupts. +//! +//! This function may be used to clear an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_int_clear(uint32_t ui32Interrupt) +{ + // + // Use the interrupt clear register to deactivate the chosen interrupt. + // + AM_REG(IOSLAVE, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Set an IOS Interrupt. +//! +//! @param ui32Interrupt - desired interrupts. +//! +//! This function may be used to set an interrupt to the NVIC. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_int_set(uint32_t ui32Interrupt) +{ + // + // Use the interrupt clear register to deactivate the chosen interrupt. + // + AM_REG(IOSLAVE, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Write to the LRAM. +//! +//! @param ui32Offset - offset into the LRAM to write. +//! @param ui8Value - value to be written. +//! +//! This function writes ui8Value to offset ui32Offset inside the LRAM. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_lram_write(uint32_t ui32Offset, uint8_t ui8Value) +{ + // + // Write the LRAM. + // + am_hal_ios_pui8LRAM[ui32Offset] = ui8Value; +} + +//***************************************************************************** +// +//! @brief Read from the LRAM. +//! +//! @param ui32Offset - offset into the LRAM to read. +//! +//! This function read from offset ui32Offset inside the LRAM. +//! +//! @return the value at ui32Offset. +// +//***************************************************************************** +uint8_t +am_hal_ios_lram_read(uint32_t ui32Offset) +{ + // + // Read the LRAM. + // + return am_hal_ios_pui8LRAM[ui32Offset]; +} + +//***************************************************************************** +// +//! @brief Check the status of an IOS Interrupt. +//! +//! @param bEnabledOnly - return only the enabled interrupt status. +//! +//! This function may be used to return the enabled interrupt status. +//! +//! @return the enabled interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_ios_int_status_get(bool bEnabledOnly) +{ + if ( bEnabledOnly ) + { + uint32_t u32RetVal = AM_REG(IOSLAVE, INTSTAT); + return u32RetVal & AM_REG(IOSLAVE, INTEN); + + } + else + { + return AM_REG(IOSLAVE, INTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Check the amount of space used in the FIFO +//! +//! This function returns the available data in the overall FIFO yet to be +//! read by the host. This takes into account the SRAM buffer and hardware FIFO +//! +//! @return Bytes used in the Overall FIFO. +// +//***************************************************************************** +uint32_t +am_hal_ios_fifo_space_used(void) +{ + uint32_t ui32Val; + uint32_t ui32Primask; + // + // Start a critical section for thread safety. + // + ui32Primask = am_hal_interrupt_master_disable(); + ui32Val = g_sSRAMBuffer.ui32Length; + ui32Val += AM_BFR(IOSLAVE, FIFOPTR, FIFOSIZ); + // + // End the critical section + // + am_hal_interrupt_master_set(ui32Primask); + return ui32Val; +} + + + +//***************************************************************************** +// +//! @brief Check the amount of space left in the FIFO +//! +//! This function returns the available space in the overall FIFO to accept +//! new data. This takes into account the SRAM buffer and hardware FIFO +//! +//! @return Bytes left in the Overall FIFO. +// +//***************************************************************************** +uint32_t +am_hal_ios_fifo_space_left(void) +{ + uint32_t ui32Val; + uint32_t ui32Primask; + // + // Start a critical section for thread safety. + // + ui32Primask = am_hal_interrupt_master_disable(); + // + // We waste one byte in HW FIFO + // + ui32Val = g_sSRAMBuffer.ui32Capacity + g_ui32HwFifoSize - 1; + ui32Val -= g_sSRAMBuffer.ui32Length; + ui32Val -= AM_BFR(IOSLAVE, FIFOPTR, FIFOSIZ); + // + // End the critical section + // + am_hal_interrupt_master_set(ui32Primask); + return ui32Val; +} + +//***************************************************************************** +// +//! @brief Check the amount of space left in the hardware FIFO +//! +//! This function reads the IOSLAVE FIFOPTR register and determines the amount +//! of space left in the IOS LRAM FIFO. +//! +//! @return Bytes left in the IOS FIFO. +// +//***************************************************************************** +static uint32_t +fifo_space_left(void) +{ + // + // We waste one byte in HW FIFO + // + return ((uint32_t)g_ui32HwFifoSize- AM_BFR(IOSLAVE, FIFOPTR, FIFOSIZ) - 1); +} + +//***************************************************************************** +// +// Helper function for managing IOS FIFO writes. +// +//***************************************************************************** +static void +fifo_write(uint8_t *pui8Data, uint32_t ui32NumBytes) +{ + uint8_t *pFifoPtr = g_pui8FIFOPtr; + uint8_t *pFifoBase = g_pui8FIFOBase; + uint8_t *pFifoEnd = g_pui8FIFOEnd; + while ( ui32NumBytes ) + { + // + // Write the data to the FIFO + // + *pFifoPtr++ = *pui8Data++; + ui32NumBytes--; + + // + // Make sure to wrap the FIFO pointer if necessary. + // + if ( pFifoPtr == pFifoEnd ) + { + pFifoPtr = pFifoBase; + } + } + g_pui8FIFOPtr = pFifoPtr; +} + +// +// Assembly code below assumes 8bit FIFOSIZ field aligned at a byte boundary +// +#if (((AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_M >> AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S) != 0xFF) \ + || (AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S & 0x3)) +#error "FIFOSIZ not 8bit value aligned at byte offset" +#endif + +// +// Byte offset of FIFOSIZ field in FIFOPTR register +// +#define BYTEOFFSET_FIFOSIZE (AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S >> 3) + +//***************************************************************************** +// +// Helper function in assembly for implementing the ReSync +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +#if (AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S != 8) +#error "AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S not 8" +#endif +__attribute__((naked)) +static void +internal_resync_fifoSize(uint32_t wrOffset, uint32_t maxFifoSize, uint32_t hwFifoPtrRegAddr) +{ + __asm + ( + " push {r3,r4}\n\t" // Save r3, r4 - used by this function + "__internal_resync_fifoSize_loop:\n\t" + " ldr r4, [r2]\n\t" // Load FIFOPTR register in r4 + " ubfx r3, r4, #8, #8\n\t" // Extract hwFifoSize to r3 + " uxtb r4, r4\n\t" // Extract rdOffset in r4 + " subs r4, r0, r4\n\t" // fifoSize in r4 = wrOffset - rdOffset + " it cc\n\t" // if (wrOffset < rdOffset) + " addcc r4, r4, r1\n\t" // fifoSize = maxFifoSize - (rdOffset - wrOffset) + " cmp r3, r4\n\t" // (hwFifoSize != fifoSize) + " beq __internal_resync_fifosize_done\n\t" + " strb r4, [r2, #1]\n\t" // Overwrite FIFOSIZ value with fifoSize + " b __internal_resync_fifoSize_loop\n\t" // Repeat the check + "__internal_resync_fifosize_done:\n\t" + " pop {r3,r4}\n\t" // Restore registers + " bx lr\n\t" + ); +} + +#elif defined(__ARMCC_VERSION) +__asm static void +internal_resync_fifoSize(uint32_t wrOffset, uint32_t maxFifoSize, uint32_t hwFifoPtrRegAddr) +{ + push {r3, r4} // Save r3, r4 - used by this function +internal_resync_fifoSize_loop + ldr r4, [r2] // Load FIFOPTR register in r4 + ubfx r3, r4, #AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S, #8 // Extract hwFifoSize to r3 + uxtb r4, r4 // Extract rdOffset in r4 + subs r4, r0, r4 // fifoSize in r4 = wrOffset - rdOffset + it cc // if (wrOffset < rdOffset), + addcc r4, r4, r1 // fifoSize = maxFifoSize - (rdOffset - wrOffset) + cmp r3, r4 // (hwFifoSize != fifoSize) + beq internal_resync_fifosize_done + strb r4, [r2, #1] // Overwrite FIFOSIZ value with fifoSize + b internal_resync_fifoSize_loop // Repeat the check +internal_resync_fifosize_done + pop {r3, r4} // Restore registers + bx lr +} + +#elif defined(__IAR_SYSTEMS_ICC__) +#if (AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S != 8) +#error "AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S not 8" +#endif +__stackless static void +internal_resync_fifoSize(uint32_t wrOffset, uint32_t maxFifoSize, uint32_t hwFifoPtrRegAddr) +{ + __asm volatile ( + " push {r3,r4}\n" // Save r3, r4 - used by this function + "__internal_resync_fifoSize_loop:\n" + " ldr r4, [r2]\n" // Load FIFOPTR register in r4 + " ubfx r3, r4, #8, #8\n" // Extract hwFifoSize to r3 + " uxtb r4, r4\n" // Extract rdOffset in r4 + " subs r4, r0, r4\n" // fifoSize in r4 = wrOffset - rdOffset + " it cc\n" + " addcc r4, r4, r1\n" // fifoSize = maxFifoSize - (rdOffset - wrOffset) + " cmp r3, r4\n" // (fifoSize != hwFifoSize) + " beq __internal_resync_fifosize_done\n" + " strb r4, [r2, #1]\n" // Overwrite FIFOSIZ value with fifoSize + " b __internal_resync_fifoSize_loop\n" // Repeat the check + "__internal_resync_fifosize_done:\n" + " pop {r3,r4}\n" // Restore registers + " bx lr\n" + ); +} + +#else +static void +internal_resync_fifoSize(uint32_t wrOffset, uint32_t maxFifoSize, uint32_t hwFifoPtrRegAddr) +{ + uint32_t fifoSize; + uint32_t hwFifoPtrReg; + uint32_t rdOffset; + uint32_t hwFifoSize; + + hwFifoPtrReg = AM_REGVAL(hwFifoPtrRegAddr); + rdOffset = ((hwFifoPtrReg & AM_REG_IOSLAVE_FIFOPTR_FIFOPTR_M) >> AM_REG_IOSLAVE_FIFOPTR_FIFOPTR_S); + hwFifoSize = (hwFifoPtrReg & AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_M) >> AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S; + // By wasting one byte in hardware FIFO, we're guaranteed that fifoSize does not need special handling for FULL FIFO case + fifoSize = ((wrOffset >= rdOffset) ? (wrOffset - rdOffset) : (maxFifoSize - (rdOffset - wrOffset))); + while ( fifoSize != hwFifoSize ) + { + // Overwite correct FIFOSIZ + // Need to do a Byte Write to make sure the FIFOPTR is not overwritten + *((uint8_t *)(hwFifoPtrRegAddr + BYTEOFFSET_FIFOSIZE)) = fifoSize; + // Read back the register and check for consistency + hwFifoPtrReg = AM_REGVAL(hwFifoPtrRegAddr); + rdOffset = ((hwFifoPtrReg & AM_REG_IOSLAVE_FIFOPTR_FIFOPTR_M) >> AM_REG_IOSLAVE_FIFOPTR_FIFOPTR_S); + hwFifoSize = (hwFifoPtrReg & AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_M) >> AM_REG_IOSLAVE_FIFOPTR_FIFOSIZ_S; + // By wasting one byte in hardware FIFO, we're guaranteed that fifoSize does not need special handling for FULL FIFO case + fifoSize = ((wrOffset >= rdOffset) ? (wrOffset - rdOffset) : (hwFifoSize - (rdOffset - wrOffset))); + } +} +#endif + +// +// Address of the FIFOPTR register +// +#define AM_REG_IOS_FIFOPTR (REG_IOSLAVE_BASEADDR + AM_REG_IOSLAVE_FIFOPTR_O) + +// When the FIFO is being replenished by the SW, at the same time as host is +// reading from it, there is a possible race condition, where the hardware decrement +// of FIFOSIZ as a result of read gets overwritten by hardware increment due to +// write. +// This function re-sync's the FIFOSIZ to ensure such errors do not accumulate +void +resync_fifoSize(void) +{ + uint32_t ui32Primask; + uint32_t wrOffset = (uint32_t)g_pui8FIFOPtr - (uint32_t)am_hal_ios_pui8LRAM; + // + // Start a critical section for thread safety. + // + ui32Primask = am_hal_interrupt_master_disable(); + internal_resync_fifoSize(wrOffset, g_ui32HwFifoSize, AM_REG_IOS_FIFOPTR); + // Clear interrupts for IOS which could be spuriously triggered + AM_REG(IOSLAVE, REGACCINTCLR) = (AM_HAL_IOS_INT_FSIZE | AM_HAL_IOS_INT_FOVFL | AM_HAL_IOS_INT_FUNDFL); + // + // End the critical section + // + am_hal_interrupt_master_set(ui32Primask); + return; +} + +//***************************************************************************** +// +//! @brief Transfer any available data from the IOS SRAM buffer to the FIFO. +//! +//! This function is meant to be called from an interrupt handler for the +//! ioslave module. It checks the IOS FIFO interrupt status for a threshold +//! event, and transfers data from an SRAM buffer into the IOS FIFO. +//! +//! @param ui32Status should be set to the ios interrupt status at the time of +//! ISR entry. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_fifo_service(uint32_t ui32Status) +{ + uint32_t thresh; + uint32_t freeSpace, usedSpace, chunk1, chunk2, ui32WriteIndex; + + // + // Check for FIFO size interrupts. + // + if ( ui32Status & AM_HAL_IOS_INT_FSIZE ) + { + thresh = AM_BFR(IOSLAVE, FIFOTHR, FIFOTHR); + + // + // While the FIFO is at or below threshold Add more data + // If Fifo level is above threshold, we're guaranteed an FSIZ interrupt + // + while ( g_sSRAMBuffer.ui32Length && + ((usedSpace = AM_BFR(IOSLAVE, FIFOPTR, FIFOSIZ)) <= thresh) ) + { + // + // So, we do have some data in SRAM which needs to be moved to FIFO. + // A chunk of data is a continguous set of bytes in SRAM that can be + // written to FIFO. Determine the chunks of data from SRAM that can + // be written. Up to two chunks possible + // + ui32WriteIndex = g_sSRAMBuffer.ui32WriteIndex; + chunk1 = ((ui32WriteIndex > (uint32_t)g_sSRAMBuffer.ui32ReadIndex) ? \ + (ui32WriteIndex - (uint32_t)g_sSRAMBuffer.ui32ReadIndex) : \ + (g_sSRAMBuffer.ui32Capacity - (uint32_t)g_sSRAMBuffer.ui32ReadIndex)); + chunk2 = g_sSRAMBuffer.ui32Length - chunk1; + // We waste one byte in HW FIFO + freeSpace = g_ui32HwFifoSize - usedSpace - 1; + // Write data in chunks + // Determine the chunks of data from SRAM that can be written + if ( chunk1 > freeSpace ) + { + fifo_write((uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), freeSpace); + // + // Advance the read index, wrapping if needed. + // + g_sSRAMBuffer.ui32ReadIndex += freeSpace; + // No need to check for wrap as we wrote less than chunk1 + // + // Adjust the length value to reflect the change. + // + g_sSRAMBuffer.ui32Length -= freeSpace; + } + else + { + fifo_write((uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), chunk1); + + // + // Update the read index - wrapping as needed + // + g_sSRAMBuffer.ui32ReadIndex += chunk1; + g_sSRAMBuffer.ui32ReadIndex %= g_sSRAMBuffer.ui32Capacity; + // + // Adjust the length value to reflect the change. + // + g_sSRAMBuffer.ui32Length -= chunk1; + freeSpace -= chunk1; + + if ( freeSpace && chunk2 ) + { + if ( chunk2 > freeSpace ) + { + fifo_write((uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), freeSpace); + + // + // Advance the read index, wrapping if needed. + // + g_sSRAMBuffer.ui32ReadIndex += freeSpace; + + // No need to check for wrap in chunk2 + // + // Adjust the length value to reflect the change. + // + g_sSRAMBuffer.ui32Length -= freeSpace; + } + else + { + fifo_write((uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), chunk2); + // + // Advance the read index, wrapping if needed. + // + g_sSRAMBuffer.ui32ReadIndex += chunk2; + + // No need to check for wrap in chunk2 + // + // Adjust the length value to reflect the change. + // + g_sSRAMBuffer.ui32Length -= chunk2; + } + } + } + resync_fifoSize(); + + // + // Need to retake the FIFO space, after Threshold interrupt has been reenabled + // Clear any spurious FSIZE interrupt that might have got raised + // + AM_BFW(IOSLAVE, INTCLR, FSIZE, 1); + } + } +} + +//***************************************************************************** +// +//! @brief Writes the specified number of bytes to the IOS fifo. +//! +//! @param pui8Data is a pointer to the data to be written to the fifo. +//! @param ui32NumBytes is the number of bytes to send. +//! +//! This function will write data from the caller-provided array to the IOS +//! LRAM FIFO. If there is no space in the LRAM FIFO, the data will be copied +//! to a temporary SRAM buffer instead. +//! +//! The maximum message size for the IO Slave is 1023 bytes. +//! +//! @note In order for SRAM copy operations in the function to work correctly, +//! the \e am_hal_ios_buffer_service() function must be called in the ISR for +//! the ioslave module. +//! +//! @return Number of bytes written (could be less than ui32NumBytes, if not enough space) +// +//***************************************************************************** +uint32_t +am_hal_ios_fifo_write(uint8_t *pui8Data, uint32_t ui32NumBytes) +{ + uint32_t ui32FIFOSpace; + uint32_t ui32SRAMSpace; + uint32_t ui32SRAMLength; + uint32_t ui32Primask; + uint32_t totalBytes = ui32NumBytes; + + // + // This operation will only work properly if an SRAM buffer has been + // allocated. Make sure that am_hal_ios_fifo_buffer_init() has been called, + // and the buffer pointer looks valid. + // + am_hal_debug_assert(g_sSRAMBuffer.pui8Data != 0); + + if ( ui32NumBytes == 0 ) + { + return 0; + } + + // + // Start a critical section for thread safety. + // + ui32Primask = am_hal_interrupt_master_disable(); + + ui32SRAMLength = g_sSRAMBuffer.ui32Length; + // + // End the critical section + // + am_hal_interrupt_master_set(ui32Primask); + + // + // If the SRAM buffer is empty, we should just write directly to the FIFO. + // + if ( ui32SRAMLength == 0 ) + { + ui32FIFOSpace = fifo_space_left(); + + // + // If the whole message fits, send it now. + // + if ( ui32NumBytes <= ui32FIFOSpace ) + { + fifo_write(pui8Data, ui32NumBytes); + ui32NumBytes = 0; + } + else + { + fifo_write(pui8Data, ui32FIFOSpace); + ui32NumBytes -= ui32FIFOSpace; + pui8Data += ui32FIFOSpace; + }; + resync_fifoSize(); + } + + // + // If there's still data, write it to the SRAM buffer. + // + if ( ui32NumBytes ) + { + uint32_t idx, writeIdx, capacity, fifoSize; + ui32SRAMSpace = g_sSRAMBuffer.ui32Capacity - ui32SRAMLength; + + writeIdx = g_sSRAMBuffer.ui32WriteIndex; + capacity = g_sSRAMBuffer.ui32Capacity; + // + // Make sure that the data will fit inside the SRAM buffer. + // + if ( ui32SRAMSpace > ui32NumBytes ) + { + ui32SRAMSpace = ui32NumBytes; + } + + // + // If the data will fit, write it to the SRAM buffer. + // + for ( idx = 0; idx < ui32SRAMSpace; idx++ ) + { + g_sSRAMBuffer.pui8Data[(idx + writeIdx) % capacity] = pui8Data[idx]; + } + + ui32NumBytes -= idx; + // + // Start a critical section for thread safety before updating length & wrIdx. + // + ui32Primask = am_hal_interrupt_master_disable(); + // + // Advance the write index, making sure to wrap if necessary. + // + g_sSRAMBuffer.ui32WriteIndex = (idx + writeIdx) % capacity; + + // + // Update the length value appropriately. + // + g_sSRAMBuffer.ui32Length += idx; + // + // End the critical section + // + am_hal_interrupt_master_set(ui32Primask); + + // It is possible that there is a race condition that the FIFO level has + // gone below the threshold by the time we set the wrIdx above, and hence + // we may never get the threshold interrupt to serve the SRAM data we + // just wrote + + // If that is the case, explicitly generate the FSIZE interrupt from here + fifoSize = AM_BFR(IOSLAVE, FIFOPTR, FIFOSIZ); + if ( fifoSize <= AM_BFR(IOSLAVE, FIFOTHR, FIFOTHR) ) + { + AM_BFW(IOSLAVE, INTSET, FSIZE, 1); + } + } + + return (totalBytes - ui32NumBytes); +} + +//***************************************************************************** +// +//! @brief Writes the specified number of bytes to the IOS fifo simply. +//! +//! @param pui8Data is a pointer to the data to be written to the fifo. +//! @param ui32NumBytes is the number of bytes to send. +//! +//! This function will write data from the caller-provided array to the IOS +//! LRAM FIFO. This simple routine does not use SRAM buffering for large +//! messages. +//! +//! The maximum message size for the IO Slave is 128 bytes. +//! +//! @note Do note call the \e am_hal_ios_buffer_service() function in the ISR for +//! the ioslave module. +//! +//! @return +// +//***************************************************************************** +void +am_hal_ios_fifo_write_simple(uint8_t *pui8Data, uint32_t ui32NumBytes) +{ + uint32_t ui32FIFOSpace; + + // + // Check the FIFO and the SRAM buffer to see where we have space. + // + ui32FIFOSpace = fifo_space_left(); + + // + // If the whole message fits, send it now. + // + if ( ui32NumBytes <= ui32FIFOSpace ) + { + fifo_write(pui8Data, ui32NumBytes); + } + else + { + // + // The message didn't fit. Try using am_hal_ios_fifo_write() instead. + // + am_hal_debug_assert_msg(0, "The requested IOS transfer didn't fit in" + "the LRAM FIFO. Try using am_hal_ios_fifo_write()."); + } +} + +//***************************************************************************** +// +//! @brief Sets the IOS FIFO pointer to the specified LRAM offset. +//! +//! @param ui32Offset is LRAM offset to set the FIFO pointer to. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_fifo_ptr_set(uint32_t ui32Offset) +{ + uint32_t ui32Primask; + + // + // Start a critical section for thread safety. + // + ui32Primask = am_hal_interrupt_master_disable(); + + // + // Set the FIFO Update bit. + // + AM_REG(IOSLAVE, FUPD) = 0x1; + + // + // Change the FIFO offset. + // + AM_REG(IOSLAVE, FIFOPTR) = ui32Offset; + + // + // Clear the FIFO update bit. + // + AM_REG(IOSLAVE, FUPD) = 0x0; + + // + // Set the global FIFO-pointer tracking variable. + // + g_pui8FIFOPtr = (uint8_t *) (REG_IOSLAVE_BASEADDR + ui32Offset); + + // + // End the critical section. + // + am_hal_interrupt_master_set(ui32Primask); +} + +//***************************************************************************** +// +// Initialize an SRAM buffer for use with the IO Slave. +// +//***************************************************************************** +static void +am_hal_ios_buffer_init(am_hal_ios_buffer_t *psBuffer, void *pvArray, + uint32_t ui32Bytes) +{ + psBuffer->ui32WriteIndex = 0; + psBuffer->ui32ReadIndex = 0; + psBuffer->ui32Length = 0; + psBuffer->ui32Capacity = ui32Bytes; + psBuffer->pui8Data = (uint8_t *)pvArray; +} + +//***************************************************************************** +// +//! @brief Poll for all host side read activity to complete. +//! +//! Poll for all host side read activity to complete. Use this before +//! calling am_hal_ios_fifo_write_simple(). +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_read_poll_complete(void) +{ + while ( AM_REG(IOSLAVE, FUPD) & AM_REG_IOSLAVE_FUPD_IOREAD_M ); +} + +//***************************************************************************** +// +//! @brief Initializes an SRAM buffer for the IOS FIFO. +//! +//! @param pui8Buffer is the SRAM buffer that will be used for IOS fifo data. +//! @param ui32BufferSize is the size of the SRAM buffer. +//! +//! This function provides the IOS HAL functions with working memory for +//! managing outgoing IOS FIFO transactions. It needs to be called at least +//! once before am_hal_ios_fifo_write() may be used. +//! +//! The recommended buffer size for the IOS FIFO is 1024 bytes. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_fifo_buffer_init(uint8_t *pui8Buffer, uint32_t ui32NumBytes) +{ + // + // Initialize the global SRAM buffer + // Total size, which is SRAM Buffer plus the hardware FIFO needs to be + // limited to 1023 + // + if ( ui32NumBytes > (1023 - g_ui32HwFifoSize + 1) ) + { + ui32NumBytes = (1023 - g_ui32HwFifoSize + 1); + } + + am_hal_ios_buffer_init(&g_sSRAMBuffer, pui8Buffer, ui32NumBytes); + + // + // Clear the FIFO State + // + AM_BFW(IOSLAVE, FIFOCTR, FIFOCTR, 0x0); + AM_BFW(IOSLAVE, FIFOPTR, FIFOSIZ, 0x0); + + am_hal_ios_fifo_ptr_set(g_ui32FifoBaseOffset); +} + +//***************************************************************************** +// +//! @brief Update the FIFOCTR to inform host of available data to read. +//! +//! This function allows the application to indicate to HAL when it is safe to +//! update the FIFOCTR. +//! +//! Application needs to implement some sort of +//! synchronization with the host to make sure host is not reading FIFOCTR while +//! it is being updated by the MCU, since the FIFOCTR read over +//! IO is not an atomic operation. +//! +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_ios_update_fifoctr(void) +{ + uint32_t ui32Val; + // Determine the available data + ui32Val = am_hal_ios_fifo_space_used(); + // Update FIFOCTR + AM_BFW(IOSLAVE, FIFOCTR, FIFOCTR, ui32Val); + return; +} + +//***************************************************************************** +// +// End the doxygen group +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_ios.h b/bsp/apollo2/libraries/drivers/hal/am_hal_ios.h new file mode 100644 index 0000000000..b166c9c6e5 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_ios.h @@ -0,0 +1,362 @@ +//***************************************************************************** +// +// am_hal_ios.h +//! @file +//! +//! @brief Functions for interfacing with the IO Slave module +//! +//! @addtogroup ios2 IO Slave (SPI/I2C) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_IOS_H +#define AM_HAL_IOS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name Interface Configuration +//! @brief Macro definitions for configuring the physical interface of the IO +//! Slave +//! +//! These macros may be used with the am_hal_ios_config_t structure to set the +//! physical parameters of the SPI/I2C slave module. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOS_USE_SPI AM_REG_IOSLAVE_CFG_IFCSEL_SPI +#define AM_HAL_IOS_SPIMODE_0 AM_REG_IOSLAVE_CFG_SPOL_SPI_MODES_0_3 +#define AM_HAL_IOS_SPIMODE_1 AM_REG_IOSLAVE_CFG_SPOL_SPI_MODES_1_2 +#define AM_HAL_IOS_SPIMODE_2 AM_REG_IOSLAVE_CFG_SPOL_SPI_MODES_1_2 +#define AM_HAL_IOS_SPIMODE_3 AM_REG_IOSLAVE_CFG_SPOL_SPI_MODES_0_3 + +#define AM_HAL_IOS_USE_I2C AM_REG_IOSLAVE_CFG_IFCSEL_I2C +#define AM_HAL_IOS_I2C_ADDRESS(n) AM_REG_IOSLAVE_CFG_I2CADDR(n) + +#define AM_HAL_IOS_LSB_FIRST AM_REG_IOSLAVE_CFG_LSB(1) +//! @} + +//***************************************************************************** +// +//! @name Register Access Interrupts +//! @brief Macro definitions for register access interrupts. +//! +//! These macros may be used with any of the +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOS_ACCESS_INT_00 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 31) +#define AM_HAL_IOS_ACCESS_INT_01 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 30) +#define AM_HAL_IOS_ACCESS_INT_02 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 29) +#define AM_HAL_IOS_ACCESS_INT_03 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 28) +#define AM_HAL_IOS_ACCESS_INT_04 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 27) +#define AM_HAL_IOS_ACCESS_INT_05 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 26) +#define AM_HAL_IOS_ACCESS_INT_06 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 25) +#define AM_HAL_IOS_ACCESS_INT_07 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 24) +#define AM_HAL_IOS_ACCESS_INT_08 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 23) +#define AM_HAL_IOS_ACCESS_INT_09 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 22) +#define AM_HAL_IOS_ACCESS_INT_0A AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 21) +#define AM_HAL_IOS_ACCESS_INT_0B AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 20) +#define AM_HAL_IOS_ACCESS_INT_0C AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 19) +#define AM_HAL_IOS_ACCESS_INT_0D AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 18) +#define AM_HAL_IOS_ACCESS_INT_0E AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 17) +#define AM_HAL_IOS_ACCESS_INT_0F AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 16) +#define AM_HAL_IOS_ACCESS_INT_13 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 15) +#define AM_HAL_IOS_ACCESS_INT_17 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 14) +#define AM_HAL_IOS_ACCESS_INT_1B AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 13) +#define AM_HAL_IOS_ACCESS_INT_1F AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 12) +#define AM_HAL_IOS_ACCESS_INT_23 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 11) +#define AM_HAL_IOS_ACCESS_INT_27 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 10) +#define AM_HAL_IOS_ACCESS_INT_2B AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 9) +#define AM_HAL_IOS_ACCESS_INT_2F AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 8) +#define AM_HAL_IOS_ACCESS_INT_33 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 7) +#define AM_HAL_IOS_ACCESS_INT_37 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 6) +#define AM_HAL_IOS_ACCESS_INT_3B AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 5) +#define AM_HAL_IOS_ACCESS_INT_3F AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 4) +#define AM_HAL_IOS_ACCESS_INT_43 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 3) +#define AM_HAL_IOS_ACCESS_INT_47 AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 2) +#define AM_HAL_IOS_ACCESS_INT_4B AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 1) +#define AM_HAL_IOS_ACCESS_INT_4F AM_REG_IOSLAVE_REGACCINTEN_REGACC((uint32_t)1 << 0) +#define AM_HAL_IOS_ACCESS_INT_ALL 0xFFFFFFFF +//! @} + +//***************************************************************************** +// +//! @name I/O Slave Interrupts +//! @brief Macro definitions for I/O slave (IOS) interrupts. +//! +//! These macros may be used with any of the +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOS_INT_FSIZE AM_REG_IOSLAVE_INTEN_FSIZE_M +#define AM_HAL_IOS_INT_FOVFL AM_REG_IOSLAVE_INTEN_FOVFL_M +#define AM_HAL_IOS_INT_FUNDFL AM_REG_IOSLAVE_INTEN_FUNDFL_M +#define AM_HAL_IOS_INT_FRDERR AM_REG_IOSLAVE_INTEN_FRDERR_M +#define AM_HAL_IOS_INT_GENAD AM_REG_IOSLAVE_INTEN_GENAD_M +#define AM_HAL_IOS_INT_IOINTW AM_REG_IOSLAVE_INTEN_IOINTW_M +#define AM_HAL_IOS_INT_XCMPWR AM_REG_IOSLAVE_INTEN_XCMPWR_M +#define AM_HAL_IOS_INT_XCMPWF AM_REG_IOSLAVE_INTEN_XCMPWF_M +#define AM_HAL_IOS_INT_XCMPRR AM_REG_IOSLAVE_INTEN_XCMPRR_M +#define AM_HAL_IOS_INT_XCMPRF AM_REG_IOSLAVE_INTEN_XCMPRF_M +#define AM_HAL_IOS_INT_ALL 0xFFFFFFFF +//! @} + +//***************************************************************************** +// +//! @name I/O Slave Interrupts triggers +//! @brief Macro definitions for I/O slave (IOS) interrupts. +//! +//! These macros may be used with am_hal_ios_int_set and am_hal_ios_int_clear +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_IOS_IOINTCTL_INT0 (0x01) +#define AM_HAL_IOS_IOINTCTL_INT1 (0x02) +#define AM_HAL_IOS_IOINTCTL_INT2 (0x04) +#define AM_HAL_IOS_IOINTCTL_INT3 (0x08) +#define AM_HAL_IOS_IOINTCTL_INT4 (0x10) +#define AM_HAL_IOS_IOINTCTL_INT5 (0x20) +//! @} + +//***************************************************************************** +// +// External variable definitions +// +//***************************************************************************** + +//***************************************************************************** +// +//! @brief LRAM pointer +//! +//! Pointer to the base of the IO Slave LRAM. +// +//***************************************************************************** +extern volatile uint8_t * const am_hal_ios_pui8LRAM; + +//***************************************************************************** +// +//! @brief Configuration structure for the IO slave module. +//! +//! This structure may be used along with the am_hal_ios_config() function to +//! select key parameters of the IO Slave module. See the descriptions of each +//! parameter within this structure for more information on what they control. +// +//***************************************************************************** +typedef struct +{ + // + //! Interface Selection + //! + //! This word selects the physical behavior of the IO Slave port. For SPI + //! mode, this word should be the logical OR of one or more of the + //! following: + //! + //! AM_HAL_IOS_USE_SPI + //! AM_HAL_IOS_SPIMODE_0 + //! AM_HAL_IOS_SPIMODE_1 + //! AM_HAL_IOS_SPIMODE_2 + //! AM_HAL_IOS_SPIMODE_3 + //! + //! For I2C mode, use the logical OR of one or more of these values instead + //! (where n is the 7 or 10-bit I2C address to use): + //! + //! AM_HAL_IOS_USE_I2C + //! AM_HAL_IOS_I2C_ADDRESS(n) + //! + //! Also, in any mode, you may OR in this value to reverse the order of + //! incoming data bits. + //! + //! AM_HAL_IOS_LSB_FIRST + // + uint32_t ui32InterfaceSelect; + + // + //! Read-Only section + //! + //! The IO Slave LRAM is split into three main sections. The first section + //! is a "Direct Write" section, which may be accessed for reads or write + //! either directly through the Apollo CPU, or over the SPI/I2C bus. The + //! "Direct Write" section always begins at LRAM offset 0x0. At the end of + //! the normal "Direct Write" space, there is a "Read Only" space, which is + //! read/write accessible to the Apollo CPU, but read-only over the I2C/SPI + //! Bus. This word selects the base address of this "Read Only" space. + //! + //! This value may be set to any multiple of 8 between 0x0 and 0x78, + //! inclusive. For the configuration to be valid, \e ui32ROBase must also + //! be less than or equal to \e ui32FIFOBase + //! + //! @note The address given here is in units of BYTES. Since the location + //! of the "Read Only" space may only be set in 8-byte increments, this + //! value must be a multiple of 8. + //! + //! For the avoidance of doubt this means 0x80 is 128 bytes. These functions + //! will shift right by 8 internally. + // + uint32_t ui32ROBase; + + // + //! FIFO section + //! + //! After the "Direct Access" and "Read Only" sections is a section of LRAM + //! allocated to a FIFO. This section is accessible by the Apollo CPU + //! through the FIFO control registers, and accessible on the SPI/I2C bus + //! through the 0x7F address. This word selects the base address of the + //! FIFO space. The FIFO will extend from the address specified here to the + //! address specified in \e ui32RAMBase. + //! + //! This value may be set to any multiple of 8 between 0x0 and 0x78, + //! inclusive. For the configuration to be valid, \e ui32FIFOBase must also + //! be greater than or equal to \e ui32ROBase. + //! + //! @note The address given here is in units of BYTES. Since the location + //! of the "FIFO" space may only be set in 8-byte increments, this value + //! must be a multiple of 8. + //! + //! For the avoidance of doubt this means 0x80 is 128 bytes. These functions + //! will shift right by 8 internally. + // + uint32_t ui32FIFOBase; + + // + //! RAM section + //! + //! At the end of the IOS LRAM, the user may allocate a "RAM" space that + //! can only be accessed by the Apollo CPU. This space will not interact + //! with the SPI/I2C bus at all, and may be used as general-purpose memory. + //! Unlike normal SRAM, this section of LRAM will retain its state through + //! Deep Sleep, so it may be used as a data retention space for + //! ultra-low-power applications. + //! + //! This value may be set to any multiple of 8 between 0x0 and 0x100, + //! inclusive. For the configuration to be valid, \e ui32RAMBase must also + //! be greater than or equal to \e ui32FIFOBase. + //! + //! @note The address given here is in units of BYTES. Since the location + //! of the "FIFO" space may only be set in 8-byte increments, this value + //! must be a multiple of 8. + //! + //! For the avoidance of doubt this means 0x80 is 128 bytes. These functions + //! will shift right by 8 internally. + // + uint32_t ui32RAMBase; + + // + //! FIFO threshold + //! + //! The IO Slave module will trigger an interrupt when the number of + //! entries in the FIFO drops below this number of bytes. + // + uint32_t ui32FIFOThreshold; + + // + // Pointer to an SRAM + // + uint8_t *pui8SRAMBuffer; +} +am_hal_ios_config_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_ios_enable(uint32_t ui32Module); +extern void am_hal_ios_disable(uint32_t ui32Module); + +// these interrupts drive the HOST side IOS interrupt pins +extern void am_hal_ios_host_int_set(uint32_t ui32Interrupt); +extern void am_hal_ios_host_int_clear(uint32_t ui32Interrupt); +extern uint32_t am_hal_ios_host_int_get(void); +extern uint32_t am_hal_ios_host_int_enable_get(void); + +extern void am_hal_ios_lram_write(uint32_t ui32Offset, uint8_t ui8Value); +extern uint8_t am_hal_ios_lram_read(uint32_t ui32Offset); + +// the following interrupts go back to the NVIC +extern void am_hal_ios_config(am_hal_ios_config_t *psConfig); +extern void am_hal_ios_access_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_ios_access_int_enable_get(void); +extern void am_hal_ios_access_int_disable(uint32_t ui32Interrupt); +extern void am_hal_ios_access_int_clear(uint32_t ui32Interrupt); +extern void am_hal_ios_access_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_ios_access_int_status_get(bool bEnabledOnly); +extern void am_hal_ios_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_ios_int_enable_get(void); +extern void am_hal_ios_int_disable(uint32_t ui32Interrupt); +extern void am_hal_ios_int_clear(uint32_t ui32Interrupt); +extern void am_hal_ios_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_ios_int_status_get(bool bEnabledOnly); + +extern void am_hal_ios_fifo_buffer_init(uint8_t *pui8Buffer, uint32_t ui32NumBytes); +extern uint32_t am_hal_ios_fifo_space_left(void); +extern uint32_t am_hal_ios_fifo_space_used(void); +extern void am_hal_ios_fifo_service(uint32_t ui32Status); +// Returns the number of bytes actually written +extern uint32_t am_hal_ios_fifo_write(uint8_t *pui8Data, uint32_t ui32NumBytes); +extern void am_hal_ios_fifo_write_simple(uint8_t *pui8Data, + uint32_t ui32NumBytes); +extern void am_hal_ios_fifo_ptr_set(uint32_t ui32Offset); +extern void am_hal_ios_update_fifoctr(void); + +extern void am_hal_ios_read_poll_complete(void); +extern void am_hal_ios_pwrctrl_enable(void); +extern void am_hal_ios_pwrctrl_disable(void); + + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_IOS_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_itm.c b/bsp/apollo2/libraries/drivers/hal/am_hal_itm.c new file mode 100644 index 0000000000..0f57c0d417 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_itm.c @@ -0,0 +1,453 @@ +//***************************************************************************** +// +// am_hal_itm.c +//! @file +//! +//! @brief Functions for operating the instrumentation trace macrocell +//! +//! @addtogroup itm2 Instrumentation Trace Macrocell (ITM) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Global Variables +// +//***************************************************************************** + +//***************************************************************************** +// +//! @brief Delays for a desired amount of microseconds. +//! +//! @note - This function is based on the similar function in am_util_delay.c, +//! please see that module for implementation details. It was necessary to +//! duplicate it here to avoid having to update every example to include the +//! am_util_delay.c module in its build. +//! +//! @returns None +// +//***************************************************************************** +void +am_hal_itm_delay_us(uint32_t ui32MicroSeconds) +{ + uint32_t ui32Iterations = ui32MicroSeconds * + (am_hal_clkgen_sysclk_get() / 3000000); + + // + // Call the BOOTROM cycle delay function + // + am_hal_flash_delay(ui32Iterations); +} + +//***************************************************************************** +// +//! @brief Enables the ITM +//! +//! This function enables the ARM ITM by setting the TRCENA bit in the DEMCR +//! register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_enable(void) +{ + if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M) + { + return; + } + + // + // To be able to access ITM registers, set the Trace Enable bit + // in the Debug Exception and Monitor Control Register (DEMCR). + // + AM_REG(SYSCTRL, DEMCR) |= AM_REG_SYSCTRL_DEMCR_TRCENA(1); + while ( !(AM_REG(SYSCTRL, DEMCR) & AM_REG_SYSCTRL_DEMCR_TRCENA(1)) ); + + // + // Write the key to the ITM Lock Access register to unlock the ITM_TCR. + // + AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL; + + // + // Set the enable bits in the ITM trace enable register, and the ITM + // control registers to enable trace data output. + // + AM_REGVAL(AM_REG_ITM_TPR_O) = 0x0000000f; + AM_REGVAL(AM_REG_ITM_TER_O) = 0xffffffff; + + // + // Write to the ITM control and status register (don't enable yet). + // + AM_REGVAL(AM_REG_ITM_TCR_O) = + AM_WRITE_SM(AM_REG_ITM_TCR_ATB_ID, 0x15) | + AM_WRITE_SM(AM_REG_ITM_TCR_TS_FREQ, 1) | + AM_WRITE_SM(AM_REG_ITM_TCR_TS_PRESCALE, 1) | + AM_WRITE_SM(AM_REG_ITM_TCR_SWV_ENABLE, 1) | + AM_WRITE_SM(AM_REG_ITM_TCR_DWT_ENABLE, 0) | + AM_WRITE_SM(AM_REG_ITM_TCR_SYNC_ENABLE, 0) | + AM_WRITE_SM(AM_REG_ITM_TCR_TS_ENABLE, 0) | + AM_WRITE_SM(AM_REG_ITM_TCR_ITM_ENABLE, 1); +} + +//***************************************************************************** +// +//! @brief Disables the ITM +//! +//! This function completely disables the ARM ITM by resetting the TRCENA bit +//! in the DEMCR register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_disable(void) +{ + + if (g_ui32HALflags & AM_HAL_FLAGS_ITMSKIPENABLEDISABLE_M) + { + return; + } + + // + // Make sure the ITM_TCR is unlocked. + // + AM_REGVAL(AM_REG_ITM_LOCKAREG_O) = AM_REG_ITM_LOCKAREG_KEYVAL; + + // + // Make sure the ITM/TPIU is not busy. + // + while ( AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1) ); + + // + // Disable the ITM. + // + for (int ix = 0; ix < 100; ix++) + { + AM_REG(ITM, TCR) &= ~AM_REG_ITM_TCR_ITM_ENABLE(1); + while ( AM_REG(ITM, TCR) & (AM_REG_ITM_TCR_ITM_ENABLE(1) | AM_REG_ITM_TCR_BUSY(1)) ); + } + + // + // Reset the TRCENA bit in the DEMCR register, which should disable the ITM + // for operation. + // + AM_REG(SYSCTRL, DEMCR) &= ~AM_REG_SYSCTRL_DEMCR_TRCENA(1); + + // + // Disable the TPIU clock source in MCU control. + // + AM_REG(MCUCTRL, TPIUCTRL) = AM_REG_MCUCTRL_TPIUCTRL_CLKSEL_0MHz | + AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS; +} + +//***************************************************************************** +// +//! @brief Checks if itm is busy and provides a delay to flush the fifo +//! +//! This function disables the ARM ITM by resetting the TRCENA bit in the DEMCR +//! register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_not_busy(void) +{ + // + // Make sure the ITM/TPIU is not busy. + // + while (AM_REG(ITM, TCR) & AM_REG_ITM_TCR_BUSY(1)); + + // + // wait for 50us for the data to flush out + // + am_hal_itm_delay_us(50); +} + +//***************************************************************************** +// +//! @brief Enables tracing on a given set of ITM ports +//! +//! @param ui8portNum - Set ports to be enabled +//! +//! Enables tracing on the ports referred to by \e ui8portNum by writing the +//! associated bit in the Trace Privilege Register in the ITM. The value for +//! ui8portNum should be the logical OR one or more of the following values: +//! +//! \e ITM_PRIVMASK_0_7 - enable ports 0 through 7 +//! \e ITM_PRIVMASK_8_15 - enable ports 8 through 15 +//! \e ITM_PRIVMASK_16_23 - enable ports 16 through 23 +//! \e ITM_PRIVMASK_24_31 - enable ports 24 through 31 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_trace_port_enable(uint8_t ui8portNum) +{ + AM_REGVAL(AM_REG_ITM_TPR_O) |= (0x00000001 << (ui8portNum>>3)); +} + +//***************************************************************************** +// +//! @brief Disable tracing on the given ITM stimulus port. +//! +//! @param ui8portNum +//! +//! Disables tracing on the ports referred to by \e ui8portNum by writing the +//! associated bit in the Trace Privilege Register in the ITM. The value for +//! ui8portNum should be the logical OR one or more of the following values: +//! +//! \e ITM_PRIVMASK_0_7 - disable ports 0 through 7 +//! \e ITM_PRIVMASK_8_15 - disable ports 8 through 15 +//! \e ITM_PRIVMASK_16_23 - disable ports 16 through 23 +//! \e ITM_PRIVMASK_24_31 - disable ports 24 through 31 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_trace_port_disable(uint8_t ui8portNum) +{ + AM_REGVAL(AM_REG_ITM_TPR_O) &= ~(0x00000001 << (ui8portNum >> 3)); +} + +//***************************************************************************** +// +//! @brief Poll the given ITM stimulus register until not busy. +//! +//! @param ui32StimReg - stimulus register +//! +//! @return true if not busy, false if busy (timed out or other error). +// +//***************************************************************************** +bool +am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg) +{ + uint32_t ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg)); + + // + // Busy waiting until it is available, non-zero means ready. + // + while (!AM_REGVAL(ui32StimAddr)); + + return true; +} + +//***************************************************************************** +// +//! @brief Writes a 32-bit value to the given ITM stimulus register. +//! +//! @param ui32StimReg - stimulus register +//! @param ui32Value - value to be written. +//! +//! Write a word to the desired stimulus register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg, uint32_t ui32Value) +{ + uint32_t ui32StimAddr; + + ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg)); + + // + // Busy waiting until it is available, non-zero means ready + // + while (!AM_REGVAL(ui32StimAddr)); + + // + // Write the register. + // + AM_REGVAL(ui32StimAddr) = ui32Value; +} + +//***************************************************************************** +// +//! @brief Writes a short to the given ITM stimulus register. +//! +//! @param ui32StimReg - stimulus register +//! @param ui16Value - short to be written. +//! +//! Write a short to the desired stimulus register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg, uint16_t ui16Value) +{ + uint32_t ui32StimAddr; + + ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg)); + + // + // Busy waiting until it is available non-zero means ready + // + while (!AM_REGVAL(ui32StimAddr)); + + // + // Write the register. + // + *((volatile uint16_t *) ui32StimAddr) = ui16Value; +} + +//***************************************************************************** +// +//! @brief Writes a byte to the given ITM stimulus register. +//! +//! @param ui32StimReg - stimulus register +//! @param ui8Value - byte to be written. +//! +//! Write a byte to the desired stimulus register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg, uint8_t ui8Value) +{ + uint32_t ui32StimAddr; + + ui32StimAddr = (AM_REG_ITM_STIM0_O + (4 * ui32StimReg)); + + // + // Busy waiting until it is available (non-zero means ready) + // + while (!AM_REGVAL(ui32StimAddr)); + + // + // Write the register. + // + *((volatile uint8_t *) ui32StimAddr) = ui8Value; +} + +//***************************************************************************** +// +//! @brief Sends a Sync Packet. +//! +//! Sends a sync packet. This can be useful for external software should it +//! become out of sync with the ITM stream. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_sync_send(void) +{ + // + // Write the register. + // + am_hal_itm_stimulus_reg_word_write(AM_HAL_ITM_SYNC_REG, + AM_HAL_ITM_SYNC_VAL); +} + +//***************************************************************************** +// +//! @brief Poll the print stimulus registers until not busy. +//! +//! @return true if not busy, false if busy (timed out or other error). +// +//***************************************************************************** +bool +am_hal_itm_print_not_busy(void) +{ + // + // Poll stimulus register allocated for printing. + // + am_hal_itm_stimulus_not_busy(0); + + + return true; +} + +//***************************************************************************** +// +//! @brief Prints a char string out of the ITM. +//! +//! @param pcString pointer to the character sting +//! +//! This function prints a sting out of the ITM. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_itm_print(char *pcString) +{ + uint32_t ui32Length = 0; + + // + // Determine the length of the string. + // + while (*(pcString + ui32Length)) + { + ui32Length++; + } + + // + // If there is no longer a word left, empty out the remaining characters. + // + while (ui32Length) + { + // + // Print string out the ITM. + // + am_hal_itm_stimulus_reg_byte_write(0, (uint8_t)*pcString++); + + // + // Subtract from length. + // + ui32Length--; + } +} +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_itm.h b/bsp/apollo2/libraries/drivers/hal/am_hal_itm.h new file mode 100644 index 0000000000..e747b0ab65 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_itm.h @@ -0,0 +1,107 @@ +//***************************************************************************** +// +// am_hal_itm.h +//! @file +//! +//! @brief Functions for accessing and configuring the ARM ITM. +//! +//! @addtogroup itm2 Instrumentation Trace Macrocell (ITM) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_ITM_H +#define AM_HAL_ITM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Sync Packet Defines +// +//***************************************************************************** +#define AM_HAL_ITM_SYNC_REG 23 +#define AM_HAL_ITM_SYNC_VAL 0xF8F8F8F8 + +//***************************************************************************** +// +// PrintF Setup +// +//***************************************************************************** +#define AM_HAL_ITM_PRINT_NUM_BYTES 1 +#define AM_HAL_ITM_PRINT_NUM_REGS 1 +extern uint32_t am_hal_itm_print_registers[AM_HAL_ITM_PRINT_NUM_REGS]; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_itm_delay_us(uint32_t ui32MicroSeconds); +extern void am_hal_itm_enable(void); +extern void am_hal_itm_disable(void); +extern void am_hal_itm_not_busy(void); +extern void am_hal_itm_sync_send(void); +extern void am_hal_itm_trace_port_enable(uint8_t ui8portNum); +extern void am_hal_itm_trace_port_disable(uint8_t ui8portNum); +extern bool am_hal_itm_stimulus_not_busy(uint32_t ui32StimReg); +extern void am_hal_itm_stimulus_reg_word_write(uint32_t ui32StimReg, + uint32_t ui32Value); +extern void am_hal_itm_stimulus_reg_short_write(uint32_t ui32StimReg, + uint16_t ui16Value); +extern void am_hal_itm_stimulus_reg_byte_write(uint32_t ui32StimReg, + uint8_t ui8Value); +extern bool am_hal_itm_print_not_busy(void); +extern void am_hal_itm_print(char *pcString); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_ITM_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.c b/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.c new file mode 100644 index 0000000000..f7b60e3c1a --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.c @@ -0,0 +1,292 @@ +//***************************************************************************** +// +// am_hal_mcuctrl.c +//! @file +//! +//! @brief Functions for interfacing with the MCUCTRL. +//! +//! @addtogroup mcuctrl2 MCU Control (MCUCTRL) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +#define LDO_TRIM_REG_ADDR (0x50023004) +#define BUCK_TRIM_REG_ADDR (0x50023000) + +//***************************************************************************** +// +// Global Variables. +// +//***************************************************************************** +// +// Define the flash sizes from CHIP_INFO. +// +const uint32_t g_am_hal_mcuctrl_flash_size[16] = +{ + 16 * 1024, /* 0x0 0x00004000 16 KB */ + 32 * 1024, /* 0x1 0x00008000 32 KB */ + 64 * 1024, /* 0x2 0x00010000 64 KB */ + 128 * 1024, /* 0x3 0x00020000 128 KB */ + 256 * 1024, /* 0x4 0x00040000 256 KB */ + 512 * 1024, /* 0x5 0x00080000 512 KB */ + 1 * 1024 * 1024, /* 0x6 0x00100000 1 MB */ + 2 * 1024 * 1024, /* 0x7 0x00200000 2 MB */ + 4 * 1024 * 1024, /* 0x8 0x00400000 4 MB */ + 8 * 1024 * 1024, /* 0x9 0x00800000 8 MB */ + 16 * 1024 * 1024, /* 0xA 0x01000000 16 MB */ + 32 * 1024 * 1024, /* 0xB 0x02000000 32 MB */ + 64 * 1024 * 1024, /* 0xC 0x04000000 64 MB */ + 128 * 1024 * 1024, /* 0xD 0x08000000 128 MB */ + 256 * 1024 * 1024, /* 0xE 0x10000000 256 MB */ + 512 * 1024 * 1024 /* 0xF 0x20000000 512 MB */ +}; + +// +// Define the SRAM sizes from CHIP_INFO. +// For Apollo2, the SRAM sizes are defined exactly the same as the flash sizes. +// +#define g_am_hal_mcuctrl_sram_size g_am_hal_mcuctrl_flash_size + +//***************************************************************************** +// +//! @brief Gets all relevant device information. +//! +//! @param psDevice is a pointer to a structure that will be used to store all +//! device info. +//! +//! This function gets the device part number, chip IDs, and revision and +//! stores them in the passed structure. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_mcuctrl_device_info_get(am_hal_mcuctrl_device_t *psDevice) +{ + // + // Read the Part Number. + // + psDevice->ui32ChipPN = AM_REG(MCUCTRL, CHIP_INFO); + + // + // Read the Chip ID0. + // + psDevice->ui32ChipID0 = AM_REG(MCUCTRL, CHIPID0); + + // + // Read the Chip ID1. + // + psDevice->ui32ChipID1 = AM_REG(MCUCTRL, CHIPID1); + + // + // Read the Chip Revision. + // + psDevice->ui32ChipRev = AM_REG(MCUCTRL, CHIPREV); + + // + // Read the Part Number. + // + psDevice->ui32ChipPN = AM_REG(MCUCTRL, CHIP_INFO); + + // + // Read the Chip ID0. + // + psDevice->ui32ChipID0 = AM_REG(MCUCTRL, CHIPID0); + + // + // Read the Chip ID1. + // + psDevice->ui32ChipID1 = AM_REG(MCUCTRL, CHIPID1); + + // + // Read the Chip Revision. + // + psDevice->ui32ChipRev = AM_REG(MCUCTRL, CHIPREV); + + // + // Read the Chip VENDOR ID. + // + psDevice->ui32VendorID = AM_REG(MCUCTRL, VENDORID); + + // + // Qualified from Part Number. + // + psDevice->ui32Qualified = + (psDevice->ui32ChipPN & AM_HAL_MCUCTRL_CHIP_INFO_QUAL_M) >> + AM_HAL_MCUCTRL_CHIP_INFO_QUAL_S; + + // + // Flash size from Part Number. + // + psDevice->ui32FlashSize = + g_am_hal_mcuctrl_flash_size[ + (psDevice->ui32ChipPN & AM_HAL_MCUCTRL_CHIP_INFO_FLASH_SIZE_M) >> + AM_HAL_MCUCTRL_CHIP_INFO_FLASH_SIZE_S]; + + // + // SRAM size from Part Number. + // + psDevice->ui32SRAMSize = + g_am_hal_mcuctrl_flash_size[ + (psDevice->ui32ChipPN & AM_HAL_MCUCTRL_CHIP_INFO_SRAM_SIZE_M) >> + AM_HAL_MCUCTRL_CHIP_INFO_SRAM_SIZE_S]; + + // + // Now, let's look at the JEDEC info. + // The full partnumber is 12 bits total, but is scattered across 2 registers. + // Bits [11:8] are 0xE. + // Bits [7:4] are 0xE for Apollo, 0xD for Apollo2. + // Bits [3:0] are defined differently for Apollo and Apollo2. + // For Apollo, the low nibble is 0x0. + // For Apollo2, the low nibble indicates flash and SRAM size. + // + psDevice->ui32JedecPN = (AM_BFR(JEDEC, PID0, PNL8) << 0); + psDevice->ui32JedecPN |= (AM_BFR(JEDEC, PID1, PNH4) << 8); + + // + // JEPID is the JEP-106 Manufacturer ID Code, which is assigned to Ambiq as + // 0x1B, with parity bit is 0x9B. It is 8 bits located across 2 registers. + // + psDevice->ui32JedecJEPID = (AM_BFR(JEDEC, PID1, JEPIDL) << 0); + psDevice->ui32JedecJEPID |= (AM_BFR(JEDEC, PID2, JEPIDH) << 4); + + // + // CHIPREV is 8 bits located across 2 registers. + // + psDevice->ui32JedecCHIPREV = (AM_BFR(JEDEC, PID2, CHIPREVH4) << 4); + psDevice->ui32JedecCHIPREV |= (AM_BFR(JEDEC, PID3, CHIPREVL4) << 0); + + // + // Let's get the Coresight ID (32-bits across 4 registers) + // For Apollo and Apollo2, it's expected to be 0xB105100D. + // + psDevice->ui32JedecCID = (AM_BFR(JEDEC, CID3, CID) << 24); + psDevice->ui32JedecCID |= (AM_BFR(JEDEC, CID2, CID) << 16); + psDevice->ui32JedecCID |= (AM_BFR(JEDEC, CID1, CID) << 8); + psDevice->ui32JedecCID |= (AM_BFR(JEDEC, CID0, CID) << 0); +} + +//***************************************************************************** +// +//! @brief Enables the fault capture registers. +//! +//! This function enables the DCODEFAULTADDR and ICODEFAULTADDR registers. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_mcuctrl_fault_capture_enable(void) +{ + // + // Enable the Fault Capture registers. + // + AM_BFW(MCUCTRL, FAULTCAPTUREEN, ENABLE, 1); +} + +//***************************************************************************** +// +//! @brief Disables the fault capture registers. +//! +//! This function disables the DCODEFAULTADDR and ICODEFAULTADDR registers. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_mcuctrl_fault_capture_disable(void) +{ + // + // Disable the Fault Capture registers. + // + AM_BFW(MCUCTRL, FAULTCAPTUREEN, ENABLE, 0); +} + +//***************************************************************************** +// +//! @brief Gets the fault status and capture registers. +//! +//! @param psFault is a pointer to a structure that will be used to store all +//! fault info. +//! +//! This function gets the status of the ICODE, DCODE, and SYS bus faults and +//! the addresses associated with the fault. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_mcuctrl_fault_status(am_hal_mcuctrl_fault_t *psFault) +{ + uint32_t ui32FaultStat; + + // + // Read the Fault Status Register. + // + ui32FaultStat = AM_REG(MCUCTRL, FAULTSTATUS); + psFault->bICODE = (ui32FaultStat & AM_REG_MCUCTRL_FAULTSTATUS_ICODE_M); + psFault->bDCODE = (ui32FaultStat & AM_REG_MCUCTRL_FAULTSTATUS_DCODE_M); + psFault->bSYS = (ui32FaultStat & AM_REG_MCUCTRL_FAULTSTATUS_SYS_M); + + // + // Read the DCODE fault capture address register. + // + psFault->ui32DCODE = AM_REG(MCUCTRL, DCODEFAULTADDR); + + // + // Read the ICODE fault capture address register. + // + psFault->ui32ICODE |= AM_REG(MCUCTRL, ICODEFAULTADDR); + + // + // Read the ICODE fault capture address register. + // + psFault->ui32SYS |= AM_REG(MCUCTRL, SYSFAULTADDR); +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.h b/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.h new file mode 100644 index 0000000000..6811006fd6 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_mcuctrl.h @@ -0,0 +1,212 @@ +//***************************************************************************** +// +// am_hal_mcuctrl.h +//! @file +//! +//! @brief Functions for accessing and configuring the MCUCTRL. +//! +//! @addtogroup mcuctrl2 MCU Control (MCUCTRL) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_MCUCTRL_H +#define AM_HAL_MCUCTRL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// +// Deprecate the am_hal_mcuctrl_bucks_enable() and disable() functions. +// This functionality is now handled in pwrctrl. +// +#define am_hal_mcuctrl_bucks_enable am_hal_pwrctrl_bucks_enable +#define am_hal_mcuctrl_bucks_disable am_hal_pwrctrl_bucks_disable + + +//***************************************************************************** +// +// Define CHIP_INFO fields, which for Apollo2 are not defined in the register +// definitions. +// +//***************************************************************************** +#define AM_HAL_MCUCTRL_CHIP_INFO_CLASS_M 0xFF000000 +#define AM_HAL_MCUCTRL_CHIP_INFO_CLASS_S 24 +#define AM_HAL_MCUCTRL_CHIP_INFO_FLASH_SIZE_M 0x00F00000 +#define AM_HAL_MCUCTRL_CHIP_INFO_FLASH_SIZE_S 20 +#define AM_HAL_MCUCTRL_CHIP_INFO_SRAM_SIZE_M 0x000F0000 +#define AM_HAL_MCUCTRL_CHIP_INFO_SRAM_SIZE_S 16 +#define AM_HAL_MCUCTRL_CHIP_INFO_REV_M 0x0000FF00 +#define AM_HAL_MCUCTRL_CHIP_INFO_REV_S 8 +#define AM_HAL_MCUCTRL_CHIP_INFO_PKG_M 0x000000C0 +#define AM_HAL_MCUCTRL_CHIP_INFO_PKG_S 6 +#define AM_HAL_MCUCTRL_CHIP_INFO_PINS_M 0x00000038 +#define AM_HAL_MCUCTRL_CHIP_INFO_PINS_S 3 +#define AM_HAL_MCUCTRL_CHIP_INFO_TEMP_M 0x00000006 +#define AM_HAL_MCUCTRL_CHIP_INFO_TEMP_S 1 +#define AM_HAL_MCUCTRL_CHIP_INFO_QUAL_M 0x00000001 +#define AM_HAL_MCUCTRL_CHIP_INFO_QUAL_S 0 + +//***************************************************************************** +// +// Apollo Number Decode. +// +//***************************************************************************** +extern const uint32_t g_am_hal_mcuctrl_flash_size[]; +extern const uint32_t g_am_hal_mcuctrl_sram_size[]; + +//***************************************************************************** +// +//! MCUCTRL device structure +// +//***************************************************************************** +typedef struct +{ + // + //! Device part number. (BCD format) + // + uint32_t ui32ChipPN; + + // + //! Unique Chip ID 0. + // + uint32_t ui32ChipID0; + + // + //! Unique Chip ID 1. + // + uint32_t ui32ChipID1; + + // + //! Chip Revision. + // + uint32_t ui32ChipRev; + + // + //! Vendor ID. + // + uint32_t ui32VendorID; + + // + //! Qualified chip. + // + uint32_t ui32Qualified; + + // + //! Flash Size. + // + uint32_t ui32FlashSize; + + // + //! SRAM Size. + // + uint32_t ui32SRAMSize; + + // + // JEDEC chip info + // + uint32_t ui32JedecPN; + uint32_t ui32JedecJEPID; + uint32_t ui32JedecCHIPREV; + uint32_t ui32JedecCID; +} +am_hal_mcuctrl_device_t; + +//***************************************************************************** +// +//! MCUCTRL fault structure +// +//***************************************************************************** +typedef struct +{ + // + //! ICODE bus fault occurred. + // + bool bICODE; + + // + //! ICODE bus fault address. + // + uint32_t ui32ICODE; + + // + //! DCODE bus fault occurred. + // + bool bDCODE; + + // + //! DCODE bus fault address. + // + uint32_t ui32DCODE; + + // + //! SYS bus fault occurred. + // + bool bSYS; + + // + //! SYS bus fault address. + // + uint32_t ui32SYS; +} +am_hal_mcuctrl_fault_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_mcuctrl_device_info_get(am_hal_mcuctrl_device_t *psDevice); +extern void am_hal_mcuctrl_fault_capture_enable(void); +extern void am_hal_mcuctrl_fault_capture_disable(void); +extern void am_hal_mcuctrl_fault_status(am_hal_mcuctrl_fault_t *psFault); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_MCUCTRL_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_otp.c b/bsp/apollo2/libraries/drivers/hal/am_hal_otp.c new file mode 100644 index 0000000000..67d08448da --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_otp.c @@ -0,0 +1,173 @@ +//***************************************************************************** +// +// am_hal_otp.c +//! @file +//! +//! @brief Functions for handling the OTP interface. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#include "am_mcu_apollo.h" +#include "am_hal_flash.h" + +//***************************************************************************** +// +//! THIS FUNCTION IS DEPRECATED! +//! Use the respective HAL flash function instead. +//! +// @brief Check if debugger is currently locked out. +// +// @param None. +// +// Determine if the debugger is already locked out. +// +// @return non-zero if debugger is currently locked out. +// Specifically: +// 0 = debugger is not locked out. +// 1 = debugger is locked out. +// +//***************************************************************************** +int +am_hal_otp_is_debugger_lockedout(void) +{ + return am_hal_flash_debugger_disable_check(); +} + +//***************************************************************************** +// +//! THIS FUNCTION IS DEPRECATED! +//! Use the respective HAL flash function instead. +//! +// @brief Lock out debugger access. +// +// @param None. +// +// This function locks out access by a debugger. +// +// @return 0 if lockout was successful or if lockout was already enabled. +// +//***************************************************************************** +int +am_hal_otp_debugger_lockout(void) +{ + return am_hal_flash_debugger_disable(); +} + +//***************************************************************************** +// +//! THIS FUNCTION IS DEPRECATED! +//! Use the respective HAL flash function instead. +//! +// @brief Lock out SRAM access. +// +// @param None. +// +// This function locks out access by a debugger to SRAM. +// +// @return 0 if lockout was successful or if lockout was already enabled. +// Low byte=0xff, byte 1 contains current value of lockout. +// Else, return value from HAL programming function. +// +//***************************************************************************** +int +am_hal_otp_sram_lockout(void) +{ + return am_hal_flash_wipe_sram_enable(); +} + +//***************************************************************************** +// +//! THIS FUNCTION IS DEPRECATED! +//! Use the respective HAL flash function instead. +//! +// @brief Set copy (read) protection. +// +// @param @u32BegAddr The beginning address to be copy protected. +// @u32EndAddr The ending address to be copy protected. +// +// @note For Apollo, the u32BegAddr parameter should be on a 16KB boundary, and +// the u32EndAddr parameter should be on a (16KB-1) boundary. Otherwise +// both parameters will be truncated/expanded to do so. +// For example, if u32BegAddr=0x1000 and u32EndAddr=0xC200, the actual +// range that protected is: 0x0 - 0xFFFF. +// +// This function enables copy protection on a given flash address range. +// +// @return 0 if copy protection was successfully enabled. +// +//***************************************************************************** +int +am_hal_otp_set_copy_protection(uint32_t u32BegAddr, uint32_t u32EndAddr) +{ + return am_hal_flash_copy_protect_set((uint32_t*)u32BegAddr, + (uint32_t*)u32EndAddr); +} + +//***************************************************************************** +// +//! THIS FUNCTION IS DEPRECATED! +//! Use the respective HAL flash function instead. +//! +// @brief Set write protection. +// +// @param @u32BegAddr The beginning address to be write protected. +// @u32EndAddr The ending address to be write protected. +// +// @note For Apollo, the u32BegAddr parameter should be on a 16KB boundary, and +// the u32EndAddr parameter should be on a (16KB-1) boundary. Otherwise +// both parameters will be truncated/expanded to do so. +// For example, if u32BegAddr=0x1000 and u32EndAddr=0xC200, the actual +// range that protected is: 0x0 - 0xFFFF. +// +// This function enables write protection on a given flash address range. +// +// @return 0 if write protection was successfully enabled. +// +//***************************************************************************** +int +am_hal_otp_set_write_protection(uint32_t u32BegAddr, uint32_t u32EndAddr) +{ + return am_hal_flash_write_protect_set((uint32_t*)u32BegAddr, + (uint32_t*)u32EndAddr); +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_otp.h b/bsp/apollo2/libraries/drivers/hal/am_hal_otp.h new file mode 100644 index 0000000000..d938e916fb --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_otp.h @@ -0,0 +1,108 @@ +//***************************************************************************** +// +// am_hal_otp.h +//! @file +//! +//! @brief Functions for handling the OTP interface. +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_OTP_H +#define AM_HAL_OTP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Define some OTP values and macros. +// +//***************************************************************************** +#define AM_HAL_OTP_SIG0 0x00 +#define AM_HAL_OTP_SIG1 0x04 +#define AM_HAL_OTP_SIG2 0x08 +#define AM_HAL_OTP_SIG3 0x0C + +#define AM_HAL_OTP_DBGR_O 0x10 +#define AM_HAL_OTP_WRITPROT0_O 0x20 +#define AM_HAL_OTP_WRITPROT1_O 0x24 +#define AM_HAL_OTP_COPYPROT0_O 0x30 +#define AM_HAL_OTP_COPYPROT1_O 0x34 + +#define AM_HAL_OTP_ADDR 0x50020000 +#define AM_HAL_OTP_DBGRPROT_ADDR (AM_HAL_OTP_ADDR + AM_HAL_OTP_DBGR_O) +#define AM_HAL_OTP_WRITPROT_ADDR (AM_HAL_OTP_ADDR + AM_HAL_OTP_WRITPROT0_O) +#define AM_HAL_OTP_COPYPROT_ADDR (AM_HAL_OTP_ADDR + AM_HAL_OTP_COPYPROT0_O) + +#define AM_HAL_OTP_CHUNKSIZE (16*1024) + +// +// Debugger port lockout macros. +// +#define AM_OTP_DBGR_LOCKOUT_S (0) +#define AM_OTP_DBGR_LOCKOUT_M (0x1 << AM_OTP_DBGR_LOCKOUT_S) +#define AM_OTP_STRM_LOCKOUT_S (1) +#define AM_OTP_STRM_LOCKOUT_M (0x1 << AM_OTP_STRM_LOCKOUT_S) +#define AM_OTP_SRAM_LOCKOUT_S (2) +#define AM_OTP_SRAM_LOCKOUT_M (0x1 << AM_OTP_SRAM_LOCKOUT_S) + +//***************************************************************************** +// +// Function prototypes +// +//***************************************************************************** +extern int am_hal_otp_is_debugger_lockedout(void); +extern int am_hal_otp_debugger_lockout(void); +extern int am_hal_otp_sram_lockout(void); +extern int am_hal_otp_set_copy_protection(uint32_t u32BegAddr, uint32_t u32EndAddr); +extern int am_hal_otp_set_write_protection(uint32_t u32BegAddr, uint32_t u32EndAddr); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_OTP_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** + diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.c b/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.c new file mode 100644 index 0000000000..45acfab995 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.c @@ -0,0 +1,158 @@ +//***************************************************************************** +// +// am_hal_pdm.c +//! @file +//! +//! @brief Functions for interfacing with Pulse Density Modulation (PDM). +//! +//! @addtogroup pdm2 DMEMS Microphon3 (PDM) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Configure the PDM module. +//! +//! This function reads the an \e am_hal_pdm_config_t structure and uses it to +//! set up the PDM module. +//! +//! Please see the information on the am_hal_pdm_config_t configuration +//! structure, found in am_hal_pdm.h, for more information on the parameters +//! that may be set by this function. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_pdm_config(am_hal_pdm_config_t *psConfig) +{ + // + // setup the PDM PCFG register + // + AM_REG(PDM, PCFG) = psConfig->ui32PDMConfigReg; + + // + // setup the PDM VCFG register + // + AM_REG(PDM, VCFG) = psConfig->ui32VoiceConfigReg; + + // + // setup the PDM FIFO Threshold register + // + AM_REG(PDM, FTHR) = psConfig->ui32FIFOThreshold; + + // + // Flush the FIFO for good measure. + // + am_hal_pdm_fifo_flush(); +} + +//***************************************************************************** +// +//! @brief Enable the PDM module. +//! +//! This function enables the PDM module in the mode previously defined by +//! am_hal_pdm_config(). +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_pdm_enable(void) +{ + AM_REG(PDM, PCFG) |= AM_REG_PDM_PCFG_PDMCORE_EN; + AM_REG(PDM, VCFG) |= ( AM_REG_PDM_VCFG_IOCLKEN_EN | + AM_REG_PDM_VCFG_PDMCLK_EN | + AM_REG_PDM_VCFG_RSTB_NORM ); +} + +//***************************************************************************** +// +//! @brief Disable the PDM module. +//! +//! This function disables the PDM module. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_pdm_disable(void) +{ + AM_REG(PDM, PCFG) &= ~ AM_REG_PDM_PCFG_PDMCORE_EN; + AM_REG(PDM, VCFG) &= ~ ( AM_REG_PDM_VCFG_IOCLKEN_EN | + AM_REG_PDM_VCFG_PDMCLK_EN | + AM_REG_PDM_VCFG_RSTB_NORM ); +} + +//***************************************************************************** +// +//! @brief Return the PDM Interrupt status. +//! +//! @param bEnabledOnly - return only the enabled interrupts. +//! +//! Use this function to get the PDM interrupt status. +//! +//! @return intrrupt status +// +//***************************************************************************** +uint32_t +am_hal_pdm_int_status_get(bool bEnabledOnly) +{ + if ( bEnabledOnly ) + { + uint32_t u32RetVal = AM_REG(PDM, INTSTAT); + return u32RetVal & AM_REG(PDM, INTEN); + } + else + { + return AM_REG(PDM, INTSTAT); + } +} + +//***************************************************************************** +// +// End the doxygen group +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.h b/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.h new file mode 100644 index 0000000000..a6e23d2698 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_pdm.h @@ -0,0 +1,665 @@ +//***************************************************************************** +// +// am_hal_pdm.h +//! @file +//! +//! @brief Functions for accessing and configuring the PDM module +//! +//! @addtogroup pdm2 Pulse Density Modulation (PDM) Input Module. +//! @ingroup apollo2hal +//! @{ + +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_PDM_H +#define AM_HAL_PDM_H + +//***************************************************************************** +// +// Macro definitions +// +//***************************************************************************** + +//***************************************************************************** +// +//! @name PDM Left Right Swap Control +//! @brief Macro definitions for the PDM LRSWAP bit field +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! left right swap bit. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_LRSWAP_ENABLE \ + AM_REG_PDM_PCFG_LRSWAP_EN +#define AM_HAL_PDM_PCFG_LRSWAP_DISABLE \ + AM_REG_PDM_PCFG_LRSWAP_NOSWAP +//! @} + +//***************************************************************************** +// +//! @name PDM Right Gain Setting +//! @brief Macro definitions for the PDM Right Gain Setting. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! right gain value. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M15DB AM_REG_PDM_PCFG_PGARIGHT_M15DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M300DB AM_REG_PDM_PCFG_PGARIGHT_M300DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M45DB AM_REG_PDM_PCFG_PGARIGHT_M45DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M60DB AM_REG_PDM_PCFG_PGARIGHT_M60DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M75DB AM_REG_PDM_PCFG_PGARIGHT_M75DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M90DB AM_REG_PDM_PCFG_PGARIGHT_M90DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M105DB AM_REG_PDM_PCFG_PGARIGHT_M105DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_M120DB AM_REG_PDM_PCFG_PGARIGHT_M120DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P105DB AM_REG_PDM_PCFG_PGARIGHT_P105DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P90DB AM_REG_PDM_PCFG_PGARIGHT_P90DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P75DB AM_REG_PDM_PCFG_PGARIGHT_P75DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P60DB AM_REG_PDM_PCFG_PGARIGHT_P60DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P45DB AM_REG_PDM_PCFG_PGARIGHT_P45DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P300DB AM_REG_PDM_PCFG_PGARIGHT_P300DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_P15DB AM_REG_PDM_PCFG_PGARIGHT_P15DB +#define AM_HAL_PDM_PCFG_RIGHT_PGA_0DB AM_REG_PDM_PCFG_PGARIGHT_0DB +//! @} + +//***************************************************************************** +// +//! @name PDM Left Gain Setting +//! @brief Macro definitions for the PDM Left Gain Setting. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! left gain value. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_LEFT_PGA_M15DB AM_REG_PDM_PCFG_PGALEFT_M15DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M300DB AM_REG_PDM_PCFG_PGALEFT_M300DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M45DB AM_REG_PDM_PCFG_PGALEFT_M45DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M60DB AM_REG_PDM_PCFG_PGALEFT_M60DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M75DB AM_REG_PDM_PCFG_PGALEFT_M75DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M90DB AM_REG_PDM_PCFG_PGALEFT_M90DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M105DB AM_REG_PDM_PCFG_PGALEFT_M105DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_M120DB AM_REG_PDM_PCFG_PGALEFT_M120DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P105DB AM_REG_PDM_PCFG_PGALEFT_P105DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P90DB AM_REG_PDM_PCFG_PGALEFT_P90DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P75DB AM_REG_PDM_PCFG_PGALEFT_P75DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P60DB AM_REG_PDM_PCFG_PGALEFT_P60DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P45DB AM_REG_PDM_PCFG_PGALEFT_P45DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P300DB AM_REG_PDM_PCFG_PGALEFT_P300DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_P15DB AM_REG_PDM_PCFG_PGALEFT_P15DB +#define AM_HAL_PDM_PCFG_LEFT_PGA_0DB AM_REG_PDM_PCFG_PGALEFT_0DB +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration MCLK Divider +//! @brief Macro definitions for the PDM MCLK Divider +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! sinc decimation rate relative to the PDM sample clock (OSR). +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_MCLKDIV_DIV1 AM_REG_PDM_PCFG_MCLKDIV_MCKDIV1 +#define AM_HAL_PDM_PCFG_MCLKDIV_DIV2 AM_REG_PDM_PCFG_MCLKDIV_MCKDIV2 +#define AM_HAL_PDM_PCFG_MCLKDIV_DIV3 AM_REG_PDM_PCFG_MCLKDIV_MCKDIV3 +#define AM_HAL_PDM_PCFG_MCLKDIV_DIV4 AM_REG_PDM_PCFG_MCLKDIV_MCKDIV4 + +#define AM_HAL_PDM_PCFG_MCLKDIV(DIV) AM_REG_PDM_PCFG_MCLKDIV(DIV) +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration SINC Decimation Rate +//! @brief Macro definitions for the PDM SINC decimation rate +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! sinc decimation rate relative to the PDM sample clock (OSR). +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_SINC_RATE(OSR) \ + AM_REG_PDM_PCFG_SINCRATE(OSR) +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration High Pass Filter Enable +//! @brief Macro definitions for the PDM ADCHPD +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! the high pass filter. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_ADCHPD_ENABLE AM_REG_PDM_PCFG_ADCHPD_EN +#define AM_HAL_PDM_PCFG_ADCHPD_DISABLE AM_REG_PDM_PCFG_ADCHPD_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration HPCUTOFF +//! @brief Macro definitions for the PDM High Pass Filter Cutoff Selector. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! high pass filter cutoff frequency. Valid range is 0 to 7. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_HPCUTOFF(HPSEL) \ + AM_REG_PDM_PCFG_HPCUTOFF(HPSEL) +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration Gain Set Change Clock Delay +//! @brief Macro definitions for the PDM clock delay for gain set changes. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! number of clocks for spreading gain setting changes. Valid range is 0 to 7. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_CYCLES(CLOCKS) \ + AM_REG_PDM_PCFG_CYCLES(CLOCKS) +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration SOFTMUTE enable/disable. +//! @brief Macro definitions for the PDM PCFG register mute controls. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the SOFTMUTE option. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_SOFTMUTE_ENABLE AM_REG_PDM_PCFG_SOFTMUTE_EN +#define AM_HAL_PDM_PCFG_SOFTMUTE_DISABLE AM_REG_PDM_PCFG_SOFTMUTE_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Configuration PDM Core enable/disable. +//! @brief Macro definitions for the PDM PCFG register filter engine enable. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM filter engine core. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_PCFG_PDMCORE_ENABLE AM_REG_PDM_PCFG_PDMCORE_EN +#define AM_HAL_PDM_PCFG_PDMCORE_DISABLE AM_REG_PDM_PCFG_PDMCORE_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Clock Frequencies +//! @brief Macro definitions for the PDM clock (from clkgen) frequencies. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! source clock frequency of the PDM interface. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_IOCLK_12MHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_12MHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_6MHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_6MHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_3MHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_3MHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_1_5MHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_1_5MHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_750KHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_750KHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_375KHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_375KHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +#define AM_HAL_PDM_IOCLK_187KHZ \ + (AM_REG_PDM_VCFG_PDMCLKSEL_187KHz | AM_REG_PDM_VCFG_IOCLKEN_EN) +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration RSTB +//! @brief Reset the IP core. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_RSTB_RESET AM_REG_PDM_VCFG_RSTB_RESET +#define AM_HAL_PDM_VCFG_RSTB_NORMAL AM_REG_PDM_VCFG_RSTB_NORM +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration PDM Clock Enable/Disable +//! @brief Macro definitions for the PDM VCFG register PDMCLKEN. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM clock output to the pad mux and from there to the world. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_PDMCLK_ENABLE AM_REG_PDM_VCFG_PDMCLK_EN +#define AM_HAL_PDM_VCFG_PDMCLK_DISABLE AM_REG_PDM_VCFG_PDMCLK_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration I2S Mode Enable/Disable +//! @brief Macro definitions for the PDM VCFG register I2SMODE. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM clock output to the pad mux and from there to the world. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_I2SMODE_ENABLE AM_REG_PDM_VCFG_I2SMODE_EN +#define AM_HAL_PDM_VCFG_I2SMODE_DISABLE AM_REG_PDM_VCFG_I2SMODE_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration BCLK Inversion Enable/Disable +//! @brief Macro definitions for the PDM VCFG register BCLKINV. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM clock output to the pad mux and from there to the world. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_BCLKINV_ENABLE AM_REG_PDM_VCFG_BCLKINV_INV +#define AM_HAL_PDM_VCFG_BCLKINV_DISABLE AM_REG_PDM_VCFG_BCLKINV_NORM +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration DMICDEL Enable/Disable +//! @brief Macro definitions for the PDM VCFG register Digital Mic Delay. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM digital microphone clock delay. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_DMICDEL_1CYC AM_REG_PDM_VCFG_DMICKDEL_1CYC +#define AM_HAL_PDM_VCFG_DMICDEL_0CYC AM_REG_PDM_VCFG_DMICKDEL_0CYC +#define AM_HAL_PDM_VCFG_DMICDEL_ENABLE AM_REG_PDM_VCFG_DMICKDEL_1CYC +#define AM_HAL_PDM_VCFG_DMICDEL_DISABLE AM_REG_PDM_VCFG_DMICKDEL_0CYC +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration Select Apps Processor (AP) versus Internal +//! @brief Macro definitions for the PDM VCFG register Digital Mic Delay. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to select +//! the Application Processor (I2S slave) mode or the Internal FIFO interface +//! to the Apollo Cortex M4. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_SELAP_I2S AM_REG_PDM_VCFG_SELAP_I2S +#define AM_HAL_PDM_VCFG_SELAP_INTERNAL AM_REG_PDM_VCFG_SELAP_INTERNAL +#define AM_HAL_PDM_VCFG_SELAP_AP_I2S AM_REG_PDM_VCFG_SELAP_I2S +#define AM_HAL_PDM_VCFG_SELAP_CM4_FIFO AM_REG_PDM_VCFG_SELAP_INTERNAL +//! @} + +//***************************************************************************** +// +//! @name PDM Voice Configuration PACK Enable/Disable +//! @brief Macro definitions for the PDM VCFG register sample packing mode. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to enable +//! or disable the PDM sample packing mode. This mode puts two 16-bit samples +//! per 32-bit FIFO word. The following packed modes are available: +//! +//! mono left: LEFT_NEW, LEFT_OLD +//! mono right: RIGHT_NEW,RIGHT_OLD +//! stereo right: LEFT, RIGHT +//! stereo right(LRSWAP): RIGHT, LEFT +//! +//! +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_PACK_ENABLE AM_REG_PDM_VCFG_PCMPACK_EN +#define AM_HAL_PDM_VCFG_PACK_DISABLE AM_REG_PDM_VCFG_PCMPACK_DIS +//! @} + +//***************************************************************************** +// +//! @name PDM Channel Selects +//! @brief Macro definitions for the PDM Channel Selection. +//! +//! These macros may be used with the am_hal_pdm_config_t structure to set the +//! channel selection for the PDM interface. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_VCFG_CHANNEL_LEFT AM_REG_PDM_VCFG_CHSET_LEFT +#define AM_HAL_PDM_VCFG_CHANNEL_RIGHT AM_REG_PDM_VCFG_CHSET_RIGHT +#define AM_HAL_PDM_VCFG_CHANNEL_STEREO AM_REG_PDM_VCFG_CHSET_STEREO +//! @} + +//***************************************************************************** +// +//! @name PDM Interrupts +//! @brief Macro definitions for the PDM interrupt status bits. +//! +//! These macros correspond to the bits in the PDM interrupt status register. +//! They may be used for any of the am_hal_pdm_int_x() functions. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_PDM_INT_UNDFL AM_REG_PDM_INTEN_UNDFL_M +#define AM_HAL_PDM_INT_OVF AM_REG_PDM_INTEN_OVF_M +#define AM_HAL_PDM_INT_FIFO AM_REG_PDM_INTEN_THR_M +//! @} + +//***************************************************************************** +// +//! @brief Configuration structure for the PDM module. +// +//***************************************************************************** +typedef struct +{ + // + //! @brief Set the PDM configuration reg with the values in this member. + //! Choose from AM_HAL_PDM_PCFG macros. + //! AM_HAL_PDM_PCFG_LRSWAP_xxx + //! AM_HAL_PDM_PCFG_RIGHT_PGA_xxx + //! AM_HAL_PDM_PCFG_LEFT_PGA_xxx + //! AM_HAL_PDM_PCFG_MCLKDIV_xxx + //! AM_HAL_PDM_PCFG_SINC_RATE() + //! AM_HAL_PDM_PCFG_ADCHPD_xxx + //! AM_HAL_PDM_PCFG_HPCUTOFF() + //! AM_HAL_PDM_PCFG_CYCLES() + //! AM_HAL_PDM_PCFG_SOFTMUTE_xxx + //! * AM_HAL_PDM_PCFG_PDMCORE_EN + //! AM_HAL_PDM_PCFG_PDMCORE_DISABLE + // + uint32_t ui32PDMConfigReg; + + // + //! @brief Set the Voice Configuration reg with the values in this member. + //! Choose from AM_HAL_PDM_VCFG macros. + //! AM_HAL_PDM_IOCLK_xxx (also sets AM_REG_PDM_VCFG_IOCLKEN_EN) + //! * AM_REG_PDM_VCFG_IOCLKEN_EN + //! * AM_HAL_PDM_VCFG_RSTB_RESET + //! AM_HAL_PDM_VCFG_RSTB_NORMAL + //! * AM_HAL_PDM_VCFG_PDMCLK_EN + //! AM_HAL_PDM_VCFG_PDMCLK_DIS + //! AM_HAL_PDM_VCFG_I2SMODE_xxx + //! AM_HAL_PDM_VCFG_BCLKINV_xxx + //! AM_HAL_PDM_VCFG_DMICDEL_xxx + //! AM_HAL_PDM_VCFG_SELAP_xxx + //! AM_HAL_PDM_VCFG_PACK_xxx + //! AM_HAL_PDM_VCFG_CHANNEL_xxx + //! + //! * = These bits are set or cleared by the HAL PDM functions + //! am_hal_pdm_enable() or am_hal_pdm_disable(). + // + uint32_t ui32VoiceConfigReg; + + // + //! @brief Select the FIFO PCM sample threshold. + //! + //! The PDM controller will generate a processor interrupt when the number + //! of entries in the FIFO goes *above* this number. + // + uint32_t ui32FIFOThreshold; +} am_hal_pdm_config_t; + +//***************************************************************************** +// +// Define function-like macros. +// +//***************************************************************************** + +//***************************************************************************** +// +//! @brief Read the FIFO depth information as an in-line macro +// +//***************************************************************************** +#define am_hal_pdm_fifo_depth_read() (AM_REG(PDM, FR)) + +//***************************************************************************** +// +//! @brief Read the FIFO READ DATA as an in-line macro +// +//***************************************************************************** +#define am_hal_pdm_fifo_data_read() (AM_REG(PDM, FRD)) + +//***************************************************************************** +// +//! @brief Flush the FIFO as an in-line macro +// +//***************************************************************************** +#define am_hal_pdm_fifo_flush() (AM_REG(PDM, FLUSH) = 0) + +//***************************************************************************** +// +//! @brief Set the PDM Configuration (PCFG) Register +//! +//! This function sets the PDM configuration register +// +//***************************************************************************** +#define am_hal_pdm_pcfg_set(Value) (AM_REG(PDM, PCFG) = Value) + +//***************************************************************************** +// +//! @brief Get the PCFG register value from PDM module. +// +//***************************************************************************** +#define am_hal_pdm_pcfg_get() (AM_REG(PDM, PCFG)) + +//***************************************************************************** +// +//! @brief Set the Voice Configuration (VCFG) Register +// +//***************************************************************************** +#define am_hal_pdm_vcfg_set(Value) (AM_REG(PDM, VCFG) = Value) + +//***************************************************************************** +// +//! @brief Get the VCFG register value from PDM module. +// +//***************************************************************************** +#define am_hal_pdm_vcfg_get() (AM_REG(PDM, VCFG)) + +//***************************************************************************** +// +//! @brief Set the FIFO Threshold +// +//***************************************************************************** +#define am_hal_pdm_thresh_set(thresh) (AM_REG(PDM, FTHR) = thresh) + +//***************************************************************************** +// +//! @brief Get the FIFO Threshold register value from PDM module. +// +//***************************************************************************** +#define am_hal_pdm_thresh_get() (AM_REG(PDM, FTHR)) + +//***************************************************************************** +// +//! @brief Set the left microphone PGA gain. +//! +//***************************************************************************** +#define am_hal_pdm_left_gain_set(gain) (AM_BFW(PDM, PCFG, PGALEFT, gain)) + +//***************************************************************************** +// +//! @brief Set the right microphone PGA gain. +// +//***************************************************************************** +#define am_hal_pdm_right_gain_set(gain) (AM_BFW(PDM, PCFG, PGARIGHT, gain)) + +//***************************************************************************** +// +//! @brief Get the left microphone PGA gain value. +// +//***************************************************************************** +#define am_hal_pdm_left_gain_get() (AM_BFR(PDM, PCFG, PGALEFT)) + +//***************************************************************************** +// +//! @brief Get the right microphone PGA gain value. +// +//***************************************************************************** +#define am_hal_pdm_right_gain_get() (AM_BFR(PDM, PCFG, PGARIGHT)) + +//***************************************************************************** +// +//! @brief Enable the Soft Mute functionality. +// +//***************************************************************************** +#define am_hal_pdm_soft_mute_enable() (AM_BFWe(PDM, PCFG, SOFTMUTE, EN)) + +//***************************************************************************** +// +//! @brief Disable the Soft Mute functionality. +// +//***************************************************************************** +#define am_hal_pdm_soft_mute_disable() (AM_BFWe(PDM, PCFG, SOFTMUTE, DIS)) + +//***************************************************************************** +// +//! @brief Enable selected PDM Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_pdm.h\n +//! AM_HAL_PDM_INT_UNDFL\n +//! AM_HAL_PDM_INT_OVF\n +//! AM_HAL_PDM_INT_FIFO\n +// +//***************************************************************************** +#define am_hal_pdm_int_enable(intrpt) (AM_REG(PDM, INTEN) |= intrpt) + +//***************************************************************************** +// +//! @brief Return the enabled PDM Interrupts. +//! +//! Use this function to return all enabled PDM interrupts. +//! +//! @return all enabled PDM interrupts as a mask.\n +//! AM_HAL_PDM_INT_UNDFL\n +//! AM_HAL_PDM_INT_OVF\n +//! AM_HAL_PDM_INT_FIFO\n +// +//***************************************************************************** +#define am_hal_pdm_int_enable_get() (AM_REG(PDM, INTEN)) + +//***************************************************************************** +// +//! @brief Disable selected PDM Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_pdm.h\n +//! AM_HAL_PDM_INT_UNDFL\n +//! AM_HAL_PDM_INT_OVF\n +//! AM_HAL_PDM_INT_FIFO\n +// +//***************************************************************************** +#define am_hal_pdm_int_disable(intrpt) (AM_REG(PDM, INTEN) &= ~intrpt) + +//***************************************************************************** +// +//! @brief Clear selected PDM Interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_pdm.h\n +//! AM_HAL_PDM_INT_UNDFL\n +//! AM_HAL_PDM_INT_OVF\n +//! AM_HAL_PDM_INT_FIFO\n +// +//***************************************************************************** +#define am_hal_pdm_int_clear(intrpt) (AM_REG(PDM, INTCLR) = intrpt) + +//***************************************************************************** +// +//! @brief Set selected PDM Interrupts. +//! +//! Use this function to set the PDM interrupts. +//! +//! @param ui32Interrupt - Use the macro bit fields provided in am_hal_pdm.h\n +//! AM_HAL_PDM_INT_UNDFL\n +//! AM_HAL_PDM_INT_OVF\n +//! AM_HAL_PDM_INT_FIFO\n +// +//***************************************************************************** +#define am_hal_pdm_int_set(intrpt) (AM_REG(PDM, INTSET) = intrpt) + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_pdm_config(am_hal_pdm_config_t * cfg); +extern void am_hal_pdm_enable(void); +extern void am_hal_pdm_disable(void); + +extern uint32_t am_hal_pdm_int_status_get(bool bEnabledOnly); + +#endif // AM_HAL_PDM_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_pin.h b/bsp/apollo2/libraries/drivers/hal/am_hal_pin.h new file mode 100644 index 0000000000..8a1068f882 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_pin.h @@ -0,0 +1,557 @@ +//***************************************************************************** +// +// am_hal_pin.h +//! @file +//! @brief Macros for configuring specific pins. +//! +//! @addtogroup pin2 PIN definitions for Apollo2. +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_PIN_H +#define AM_HAL_PIN_H + +//***************************************************************************** +// +// Pin definition helper macros. +// +//***************************************************************************** +#define AM_HAL_PIN_DIR_INPUT (AM_HAL_GPIO_INPEN) +#define AM_HAL_PIN_DIR_OUTPUT (AM_HAL_GPIO_OUT_PUSHPULL) +#define AM_HAL_PIN_DIR_OPENDRAIN (AM_HAL_GPIO_OUT_OPENDRAIN | AM_HAL_GPIO_INPEN) +#define AM_HAL_PIN_DIR_3STATE (AM_HAL_GPIO_OUT_3STATE) + +//***************************************************************************** +// +// Pin definition helper macros. +// +//***************************************************************************** +#define AM_HAL_PIN_DISABLE (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_INPUT (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_OUTPUT (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_OUTPUT) +#define AM_HAL_PIN_OPENDRAIN (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_3STATE (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_3STATE) + +//***************************************************************************** +// +// Pin definition macros. +// +//***************************************************************************** +#define AM_HAL_PIN_0_SLSCL (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_0_SLSCK (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_0_CLKOUT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_0_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_0_MxSCKLB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_0_M2SCK (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_0_MxSCLLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_0_M2SCL (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_OPENDRAIN) + +#define AM_HAL_PIN_1_SLSDA (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_1_SLMISO (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_1_UART0TX (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_1_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_1_MxMISOLB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_1_M2MISO (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_1_MxSDALB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_1_M2SDA (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_OPENDRAIN) + +#define AM_HAL_PIN_2_SLWIR3 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_2_SLMOSI (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_2_UART0RX (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_2_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_2_MxMOSILB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_2_M2MOSI (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_2_MxWIR3LB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_2_M2WIR3 (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_3STATE) + +#define AM_HAL_PIN_3_UART0RTS (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_3_SLnCE (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_3_M1nCE4 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_3_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_3_MxnCELB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_3_M2nCE0 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_3_TRIG1 (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_3_I2S_WCLK (AM_HAL_GPIO_FUNC(7)) +#define AM_HAL_PIN_3_PSOURCE (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_OUTPUT | AM_HAL_GPIO_POWER) + +#define AM_HAL_PIN_4_UART0CTS (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_4_SLINT (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_4_M0nCE5 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_4_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_4_SLINTGP (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_4_M2nCE5 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_4_CLKOUT (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_4_32KHZ_XT (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_5_M0SCL (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_5_M0SCK (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_5_UART0RTS (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_5_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_5_M0SCKLB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_5_EXTHFA (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_5_M0SCLLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_5_M1nCE2 (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_6_M0SDA (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_6_M0MISO (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_6_UART0CTS (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_6_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_6_SLMISOLB (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_6_M1nCE0 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_6_SLSDALB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_6_I2S_DAT (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_7_M0WIR3 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_7_M0MOSI (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_7_CLKOUT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_7_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_7_TRIG0 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_7_UART0TX (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_7_SLWIR3LB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_7_M1nCE1 (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_8_M1SCL (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_8_M1SCK (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_8_M0nCE4 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_8_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_8_M2nCE4 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_8_M1SCKLB (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_8_UART1TX (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_8_M1SCLLB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_9_M1SDA (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_9_M1MISO (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_9_M0nCE5 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_9_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_9_M4nCE5 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_9_SLMISOLB (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_9_UART1RX (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_9_SLSDALB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_10_M1WIR3 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_10_M1MOSI (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_10_M0nCE6 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_10_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_10_M2nCE6 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_10_UART1RTS (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_10_M4nCE4 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_10_SLWIR3LB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_11_ADCSE2 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_11_M0nCE0 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_11_CLKOUT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_11_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_11_M2nCE7 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_11_UART1CTS (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_11_UART0RX (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_11_PDM_DATA (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_11_PSINK (AM_HAL_GPIO_FUNC(3)) + +#define AM_HAL_PIN_12_ADCD0NSE9 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_12_M1nCE0 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_12_TCTA0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_12_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_12_CLKOUT (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_12_PDM_CLK (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_12_UART0CTS (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_12_UART1TX (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_13_ADCD0PSE8 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_13_M1nCE1 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_13_TCTB0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_13_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_13_M2nCE3 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_13_EXTHFB (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_13_UART0RTS (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_13_UART1RX (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) + +#define AM_HAL_PIN_14_ADCD1P (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_14_M1nCE2 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_14_UART1TX (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_14_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_14_M2nCE1 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_14_EXTHFS (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_14_SWDCK (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_14_32KHZ_XT (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_15_ADCD1N (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_15_M1nCE3 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_15_UART1RX (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_15_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_15_M2nCE2 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_15_EXTXT (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_15_SWDIO (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_15_SWO (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_16_ADCSE0 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_16_M0nCE4 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_16_TRIG0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_16_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_16_M2nCE3 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_16_CMPIN0 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_16_UART0TX (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_16_UART1RTS (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_17_CMPRF1 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_17_M0nCE1 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_17_TRIG1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_17_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_17_M4nCE3 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_17_EXTLF (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_17_UART0RX (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_17_UART1CTS (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) + +#define AM_HAL_PIN_18_CMPIN1 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_18_M0nCE2 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_18_TCTA1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_18_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_18_M4nCE1 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_18_ANATEST2 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_18_UART1TX (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_18_32KHZ_XT (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_19_CMPRF0 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_19_M0nCE3 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_19_TCTB1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_19_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_19_TCTA1 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_19_ANATEST1 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_19_UART1RX (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_19_I2S_BCLK (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_20_SWDCK (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_20_M1nCE5 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_20_TCTA2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_20_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_20_UART0TX (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_20_UART1TX (AM_HAL_GPIO_FUNC(5)) + +#define AM_HAL_PIN_21_SWDIO (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_21_M1nCE6 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_21_TCTB2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_21_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_21_UART0RX (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_21_UART1RX (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) + +#define AM_HAL_PIN_22_UART0TX (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_22_M1nCE7 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_22_TCTA3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_22_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_22_PDM_CLK (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_22_TCTB1 (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_22_SWO (AM_HAL_GPIO_FUNC(7)) +#define AM_HAL_PIN_22_PSOURCE (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_OUTPUT | AM_HAL_GPIO_POWER) + +#define AM_HAL_PIN_23_UART0RX (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_23_M0nCE0 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_23_TCTB3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_23_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_23_PDM_DATA (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_23_CMPOUT (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_23_TCTB1 (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_24_M2nCE1 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_24_M0nCE1 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_24_CLKOUT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_24_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_24_M5nCE0 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_24_TCTA1 (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_24_I2S_BCLK (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_24_SWO (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_25_EXTXT (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_25_M0nCE2 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_25_TCTA0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_25_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_25_M2SDA (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_25_M2MISO (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_25_SLMISOLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_25_SLSDALB (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#define AM_HAL_PIN_26_EXTLF (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_26_M0nCE3 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_26_TCTB0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_26_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_26_M2nCE0 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_26_TCTA1 (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_26_M5nCE1 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_26_M3nCE0 (AM_HAL_GPIO_FUNC(7)) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_27_EXTHF (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_27_M1nCE4 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_27_TCTA1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_27_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_27_M2SCL (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_27_M2SCK (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_27_M2SCKLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_27_M2SCLLB (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#define AM_HAL_PIN_28_I2S_WCLK (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_28_M1nCE5 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_28_TCTB1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_28_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_28_M2WIR3 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_28_M2MOSI (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_28_M5nCE3 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_28_SLWIR3LB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_29_ADCSE1 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_29_M1nCE6 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_29_TCTA2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_29_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_29_UART0CTS (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_29_UART1CTS (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_29_M4nCE0 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_29_PDM_DATA (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_30_M1nCE7 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_30_TCTB2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_30_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_30_UART0TX (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_30_UART1RTS (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_30_SWO (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_30_I2S_DAT (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_31_ADCSE3 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_31_M0nCE4 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_31_TCTA3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_31_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_31_UART0RX (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_31_TCTB1 (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_32_ADCSE4 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_32_M0nCE5 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_32_TCTB3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_32_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_32_TCTB1 (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_33_ADCSE5 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_33_M0nCE6 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_33_32KHZ_XT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_33_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_33_M3nCE7 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_33_TCTB1 (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_33_SWO (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_34_ADCSE6 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_34_M0nCE7 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_34_M2nCE3 (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_34_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_34_CMPRF2 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_34_M3nCE1 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_34_M4nCE0 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_34_M5nCE2 (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_35_ADCSE7 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_35_M1nCE0 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_35_UART1TX (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_35_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_35_M4nCE6 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_35_TCTA1 (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_35_UART0RTS (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_35_M3nCE2 (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_36_TRIG1 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_36_M1nCE1 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_36_UART1RX (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_36_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_36_32KHZ_XT (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_36_M2nCE0 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_36_UART0CTS (AM_HAL_GPIO_FUNC(6) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_36_M3nCE3 (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_37_TRIG2 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_37_M1nCE2 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_37_UART0RTS (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_37_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_37_M3nCE4 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_37_M4nCE1 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_37_PDM_CLK (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_37_TCTA1 (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_38_TRIG3 (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_38_M1nCE3 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_38_UART0CTS (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_38_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_38_M3WIR3 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_38_M3MOSI (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_38_M4nCE7 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_38_SLWIR3LB (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#define AM_HAL_PIN_39_UART0TX (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_39_UART1TX (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_39_CLKOUT (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_39_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_39_M4SCL (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_39_M4SCK (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_39_M4SCKLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_39_M4SCLLB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_40_UART0RX (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_40_UART1RX (AM_HAL_GPIO_FUNC(1) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_40_TRIG0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_40_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_40_M4SDA (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_40_M4MISO (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_40_SLMISOLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_40_SLSDALB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_41_M2nCE1 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_41_CLKOUT (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_41_SWO (AM_HAL_GPIO_FUNC(2)) +#define AM_HAL_PIN_41_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_41_M3nCE5 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_41_M5nCE7 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_41_M4nCE2 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_41_UART0RTS (AM_HAL_GPIO_FUNC(7)) +#define AM_HAL_PIN_41_PSOURCE (AM_HAL_GPIO_FUNC(3) | AM_HAL_PIN_DIR_OUTPUT | AM_HAL_GPIO_POWER) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_42_M2nCE2 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_42_M0nCE0 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_42_TCTA0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_42_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_42_M3SCL (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_42_M3SCK (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_42_M3SCKLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_42_M3SCLLB (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_43_M2nCE4 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_43_M0nCE1 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_43_TCTB0 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_43_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_43_M3SDA (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_43_M3MISO (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_43_SLMISOLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_43_SLSDALB (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#define AM_HAL_PIN_44_UART1RTS (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_44_M0nCE2 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_44_TCTA1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_44_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_44_M4WIR3 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_44_M4MOSI (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_44_M5nCE6 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_44_SLWIR3LB (AM_HAL_GPIO_FUNC(7)) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_45_UART1CTS (AM_HAL_GPIO_FUNC(0) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_45_M0nCE3 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_45_TCTB1 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_45_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_45_M4nCE3 (AM_HAL_GPIO_FUNC(4)) +#define AM_HAL_PIN_45_M3nCE6 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_45_M5nCE5 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_45_TCTA1 (AM_HAL_GPIO_FUNC(7) | AM_HAL_PIN_DIR_INPUT) +#endif // defined (AM_PACKAGE_BGA) + +#if defined (AM_PACKAGE_BGA) +#define AM_HAL_PIN_46_32KHZ_XT (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_46_M0nCE4 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_46_TCTA2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_46_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_46_TCTA1 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_46_M5nCE4 (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_46_M4nCE4 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_46_SWO (AM_HAL_GPIO_FUNC(7)) +#endif // defined (AM_PACKAGE_BGA) + +#define AM_HAL_PIN_47_M2nCE5 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_47_M0nCE5 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_47_TCTB2 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_47_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_47_M5WIR3 (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_3STATE) +#define AM_HAL_PIN_47_M5MOSI (AM_HAL_GPIO_FUNC(5)) +#define AM_HAL_PIN_47_M4nCE5 (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_47_SLWIR3LB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_48_M2nCE6 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_48_M0nCE6 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_48_TCTA3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_48_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_48_M5SCL (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_48_M5SCK (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_48_M5SCKLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_48_M5SCLLB (AM_HAL_GPIO_FUNC(7)) + +#define AM_HAL_PIN_49_M2nCE7 (AM_HAL_GPIO_FUNC(0)) +#define AM_HAL_PIN_49_M0nCE7 (AM_HAL_GPIO_FUNC(1)) +#define AM_HAL_PIN_49_TCTB3 (AM_HAL_GPIO_FUNC(2) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_49_GPIO (AM_HAL_GPIO_FUNC(3)) +#define AM_HAL_PIN_49_M5SDA (AM_HAL_GPIO_FUNC(4) | AM_HAL_PIN_DIR_OPENDRAIN) +#define AM_HAL_PIN_49_M5MISO (AM_HAL_GPIO_FUNC(5) | AM_HAL_PIN_DIR_INPUT) +#define AM_HAL_PIN_49_SLMISOLB (AM_HAL_GPIO_FUNC(6)) +#define AM_HAL_PIN_49_SLSDALB (AM_HAL_GPIO_FUNC(7)) + +#endif // AM_HAL_PIN_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.c b/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.c new file mode 100644 index 0000000000..cc91eeb159 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.c @@ -0,0 +1,558 @@ +//***************************************************************************** +// +// am_hal_pwrctrl.c +//! @file +//! +//! @brief Functions for enabling and disabling power domains. +//! +//! @addtogroup pwrctrl2 Power Control +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// ONE_BIT - true iff value has exactly 1 bit set. +// +//***************************************************************************** +#define ONE_BIT(ui32Value) (ui32Value && !(ui32Value & (ui32Value - 1))) + +//***************************************************************************** +// +// Determine if this is an Apollo2 revision that requires additional handling +// of the BUCK to LDO transition when only the ADC is in use and going to +// deepsleep. +// +//***************************************************************************** +static bool +isRev_ADC(void) +{ + return AM_BFM(MCUCTRL, CHIPREV, REVMAJ) == AM_REG_MCUCTRL_CHIPREV_REVMAJ_B ? + true : false; +} + +//***************************************************************************** +// +//! @brief Enable power for a peripheral. +//! +//! @param ui32Peripheral - The peripheral to enable +//! +//! This function directly enables or disables power for the chosen peripheral. +//! +//! @note Unpowered peripherals may lose their configuration information. This +//! function does not save or restore peripheral configuration registers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_pwrctrl_periph_enable(uint32_t ui32Peripheral) +{ + + am_hal_debug_assert_msg(ONE_BIT(ui32Peripheral), + "Cannot enable more than one peripheral at a time."); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Enable power control for the given device. + // + AM_REG(PWRCTRL, DEVICEEN) |= ui32Peripheral; + + // + // End Critical Section. + // + AM_CRITICAL_END_ASM + + // + // Wait for the power to stablize. Using a simple delay loop is more + // power efficient than a polling loop. + // + am_hal_flash_delay(AM_HAL_PWRCTRL_DEVICEEN_DELAYCYCLES / 3); + + // + // Quick check to guarantee we're good (should never be more than 1 read). + // + POLL_PWRSTATUS(ui32Peripheral); +} + +//***************************************************************************** +// +//! @brief Disable power for a peripheral. +//! +//! @param ui32Peripheral - The peripheral to disable +//! +//! This function directly disables or disables power for the chosen peripheral. +//! +//! @note Unpowered peripherals may lose their configuration information. This +//! function does not save or restore peripheral configuration registers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_pwrctrl_periph_disable(uint32_t ui32Peripheral) +{ + + am_hal_debug_assert_msg(ONE_BIT(ui32Peripheral), + "Cannot enable more than one peripheral at a time."); + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Disable power control for the given device. + // + AM_REG(PWRCTRL, DEVICEEN) &= ~ui32Peripheral; + + // + // End critical section. + // + AM_CRITICAL_END_ASM + + // + // Wait for the power to stablize + // + am_hal_flash_delay(AM_HAL_PWRCTRL_DEVICEDIS_DELAYCYCLES / 3); +} + +//***************************************************************************** +// +//! @brief Enable and disable power for memory devices (SRAM, flash, cache). +//! +//! @param ui32MemEn - The memory and amount to be enabled. +//! Must be one of the following: +//! AM_HAL_PWRCTRL_MEMEN_CACHE +//! AM_HAL_PWRCTRL_MEMEN_CACHE_DIS +//! AM_HAL_PWRCTRL_MEMEN_FLASH512K +//! AM_HAL_PWRCTRL_MEMEN_FLASH1M +//! AM_HAL_PWRCTRL_MEMEN_SRAM8K +//! AM_HAL_PWRCTRL_MEMEN_SRAM16K +//! AM_HAL_PWRCTRL_MEMEN_SRAM24K +//! AM_HAL_PWRCTRL_MEMEN_SRAM32K +//! AM_HAL_PWRCTRL_MEMEN_SRAM64K +//! AM_HAL_PWRCTRL_MEMEN_SRAM96K +//! AM_HAL_PWRCTRL_MEMEN_SRAM128K +//! AM_HAL_PWRCTRL_MEMEN_SRAM160K +//! AM_HAL_PWRCTRL_MEMEN_SRAM192K +//! AM_HAL_PWRCTRL_MEMEN_SRAM224K +//! AM_HAL_PWRCTRL_MEMEN_SRAM256K +//! AM_HAL_PWRCTRL_MEMEN_ALL (the default, power-up state) +//! +//! This function enables/disables power to provide only the given amount of +//! the type of memory specified. +//! +//! Only the type of memory specified is affected. Therefore separate calls +//! are required to affect power settings for FLASH, SRAM, or CACHE. +//! +//! Settings for zero SRAM or FLASH are not provided as device behavior under +//! either of those conditions is undefined. +//! +//! @note Unpowered memory devices may lose their configuration information. +//! This function does not save or restore peripheral configuration registers. +//! +//! @return None. +// +//***************************************************************************** +bool +am_hal_pwrctrl_memory_enable(uint32_t ui32MemEn) +{ + uint32_t ui32MemEnMask, ui32MemDisMask; + uint32_t ui32PwrStatEnMask, ui32PwrStatDisMask; + int32_t i32TOcnt; + + if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_FLASH512K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_FLASH0_EN; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_FLASH1_EN; + ui32PwrStatEnMask = AM_REG_PWRCTRL_PWRONSTATUS_PD_FLAM0_M; + ui32PwrStatDisMask = AM_REG_PWRCTRL_PWRONSTATUS_PD_FLAM1_M; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_FLASH1M ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_FLASH0_EN | + AM_REG_PWRCTRL_MEMEN_FLASH1_EN; + ui32MemDisMask = 0; + ui32PwrStatEnMask = AM_REG_PWRCTRL_PWRONSTATUS_PD_FLAM0_M | + AM_REG_PWRCTRL_PWRONSTATUS_PD_FLAM1_M; + ui32PwrStatDisMask = 0; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM8K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM8K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM8K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_8K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_8K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM16K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM16K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM16K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_16K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_16K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM24K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM0 | + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM1 | + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM2; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~(AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM0 | + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM1 | + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM2); + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_24K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_24K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM32K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM32K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM32K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_32K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_32K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM64K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM64K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM64K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_64K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_64K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM96K ) + { + ui32MemEnMask = AM_HAL_PWRCTRL_MEMEN_SRAM96K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_HAL_PWRCTRL_MEMEN_SRAM96K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_96K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_96K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM128K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_128K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_128K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM160K ) + { + ui32MemEnMask = AM_HAL_PWRCTRL_MEMEN_SRAM160K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_HAL_PWRCTRL_MEMEN_SRAM160K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_160K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_160K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM192K ) + { + ui32MemEnMask = AM_HAL_PWRCTRL_MEMEN_SRAM192K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_HAL_PWRCTRL_MEMEN_SRAM192K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_192K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_192K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM224K ) + { + ui32MemEnMask = AM_HAL_PWRCTRL_MEMEN_SRAM224K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_HAL_PWRCTRL_MEMEN_SRAM224K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_224K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_224K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_SRAM256K ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM256K; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL & + ~AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM256K; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_256K; + ui32PwrStatDisMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL & + ~AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_256K; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_CACHE ) + { + ui32MemEnMask = AM_REG_PWRCTRL_MEMEN_CACHEB0_EN | + AM_REG_PWRCTRL_MEMEN_CACHEB2_EN; + ui32MemDisMask = 0; + ui32PwrStatEnMask = AM_REG_PWRCTRL_PWRONSTATUS_PD_CACHEB2_M | + AM_REG_PWRCTRL_PWRONSTATUS_PD_CACHEB0_M; + ui32PwrStatDisMask = 0; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_CACHE_DIS ) + { + ui32MemEnMask = 0; + ui32MemDisMask = AM_REG_PWRCTRL_MEMEN_CACHEB0_EN | + AM_REG_PWRCTRL_MEMEN_CACHEB2_EN; + ui32PwrStatEnMask = 0; + ui32PwrStatDisMask = AM_REG_PWRCTRL_PWRONSTATUS_PD_CACHEB2_M | + AM_REG_PWRCTRL_PWRONSTATUS_PD_CACHEB0_M; + } + else if ( ui32MemEn == AM_HAL_PWRCTRL_MEMEN_ALL ) + { + ui32MemEnMask = AM_HAL_PWRCTRL_MEMEN_ALL; + ui32MemDisMask = 0; + ui32PwrStatEnMask = AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL; + ui32PwrStatDisMask = 0; + } + else + { + return false; + } + + // + // Disable unneeded memory. If nothing to be disabled, skip to save time. + // + // Note that a deliberate disable step using a disable mask is taken here + // for 2 reasons: 1) To only affect the specified type of memory, and 2) + // To avoid inadvertently disabling any memory currently being depended on. + // + if ( ui32MemDisMask != 0 ) + { + AM_REG(PWRCTRL, MEMEN) &= ~ui32MemDisMask; + } + + // + // Enable the required memory. + // + if ( ui32MemEnMask != 0 ) + { + AM_REG(PWRCTRL, MEMEN) |= ui32MemEnMask; + } + + // + // Wait for the power to be turned on. + // Apollo2 note - these loops typically end up taking 1 iteration. + // + i32TOcnt = 200; + if ( ui32PwrStatDisMask ) + { + while ( --i32TOcnt && + ( AM_REG(PWRCTRL, PWRONSTATUS) & ui32PwrStatDisMask ) ); + } + + if ( i32TOcnt <= 0 ) + { + return false; + } + + i32TOcnt = 200; + if ( ui32PwrStatEnMask ) + { + while ( --i32TOcnt && + (( AM_REG(PWRCTRL, PWRONSTATUS) & ui32PwrStatEnMask ) + != ui32PwrStatEnMask) ); + } + if ( i32TOcnt <= 0 ) + { + return false; + } + + return true; +} + +//***************************************************************************** +// +//! @brief Initialize the core and memory buck converters. +//! +//! This function is intended to be used for first time core and memory buck +//! converters initialization. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_pwrctrl_bucks_init(void) +{ + am_hal_pwrctrl_bucks_enable(); + + while ( ( AM_REG(PWRCTRL, POWERSTATUS) & + ( AM_REG_PWRCTRL_POWERSTATUS_COREBUCKON_M | + AM_REG_PWRCTRL_POWERSTATUS_MEMBUCKON_M ) ) != + ( AM_REG_PWRCTRL_POWERSTATUS_COREBUCKON_M | + AM_REG_PWRCTRL_POWERSTATUS_MEMBUCKON_M ) ); + + // + // Additional delay to make sure BUCKs are initialized. + // + am_hal_flash_delay(200 / 3); +} + +//***************************************************************************** +// +//! @brief Enable the core and memory buck converters. +//! +//! This function enables the core and memory buck converters. +//! +//! @return None +// +//***************************************************************************** +#define LDO_TRIM_REG_ADDR (0x50023004) +#define BUCK_TRIM_REG_ADDR (0x50023000) + +void +am_hal_pwrctrl_bucks_enable(void) +{ + // + // Check to see if the bucks are already on. If so, we can just return. + // + if ( AM_BFR(PWRCTRL, POWERSTATUS, COREBUCKON) && + AM_BFR(PWRCTRL, POWERSTATUS, MEMBUCKON) ) + { + return; + } + + // + // Enable BUCK power up + // + AM_BFW(PWRCTRL, SUPPLYSRC, COREBUCKEN, 1); + AM_BFW(PWRCTRL, SUPPLYSRC, MEMBUCKEN, 1); + + // + // Make sure bucks are ready. + // + while ( ( AM_REG(PWRCTRL, POWERSTATUS) & + ( AM_REG_PWRCTRL_POWERSTATUS_COREBUCKON_M | + AM_REG_PWRCTRL_POWERSTATUS_MEMBUCKON_M ) ) != + ( AM_REG_PWRCTRL_POWERSTATUS_COREBUCKON_M | + AM_REG_PWRCTRL_POWERSTATUS_MEMBUCKON_M ) ); +} + +//***************************************************************************** +// +//! @brief Disable the core and memory buck converters. +//! +//! This function disables the core and memory buck converters. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_pwrctrl_bucks_disable(void) +{ + // + // Check to see if the bucks are already off. If so, we can just return. + // + if ( AM_BFR(PWRCTRL, POWERSTATUS, COREBUCKON) == 0 && + AM_BFR(PWRCTRL, POWERSTATUS, MEMBUCKON) == 0) + { + return; + } + + // + // Handle the special case if only the ADC is powered. + // + if ( isRev_ADC() && + (AM_REG(PWRCTRL, DEVICEEN) == AM_REG_PWRCTRL_DEVICEEN_ADC_EN) ) + { + // + // Set SUPPLYSRC to handle this case + // + AM_REG(PWRCTRL, SUPPLYSRC) &= + (AM_REG_PWRCTRL_SUPPLYSRC_SWITCH_LDO_IN_SLEEP_EN | + AM_REG_PWRCTRL_SUPPLYSRC_MEMBUCKEN_EN); + } + else + { + // + // Power them down + // + AM_BFW(PWRCTRL, SUPPLYSRC, COREBUCKEN, 0); + AM_BFW(PWRCTRL, SUPPLYSRC, MEMBUCKEN, 0); + } + + // + // Wait until BUCKs are disabled. + // + am_hal_flash_delay(AM_HAL_PWRCTRL_BUCKDIS_DELAYCYCLES / 3); +} + +//***************************************************************************** +// +//! @brief Misc low power initializations. +//! +//! This function performs low power initializations that aren't specifically +//! handled elsewhere. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_pwrctrl_low_power_init(void) +{ + // + // For lowest power, we enable clock gating for all SRAM configuration. + // + AM_REG(PWRCTRL, SRAMCTRL) |= + AM_REG_PWRCTRL_SRAMCTRL_SRAM_MASTER_CLKGATE_EN | + AM_REG_PWRCTRL_SRAMCTRL_SRAM_CLKGATE_EN | + AM_REG_PWRCTRL_SRAMCTRL_SRAM_LIGHT_SLEEP_DIS; + + // + // For lowest deep sleep power, make sure we stay in BUCK mode. + // + AM_REG(PWRCTRL, SUPPLYSRC) &= + ~AM_REG_PWRCTRL_SUPPLYSRC_SWITCH_LDO_IN_SLEEP_M; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.h b/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.h new file mode 100644 index 0000000000..bc9adabf84 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_pwrctrl.h @@ -0,0 +1,342 @@ +//***************************************************************************** +// +// am_hal_pwrctrl.h +//! @file +//! +//! @brief Functions for enabling and disabling power domains. +//! +//! @addtogroup pwrctrl2 Power Control +//! @ingroup apollo2hal +//! @{ + +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#ifndef AM_HAL_PWRCTRL_H +#define AM_HAL_PWRCTRL_H + +//***************************************************************************** +// +// Peripheral enable bits for am_hal_pwrctrl_periph_enable/disable() +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_ADC AM_REG_PWRCTRL_DEVICEEN_ADC_EN +#define AM_HAL_PWRCTRL_IOM0 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_EN +#define AM_HAL_PWRCTRL_IOM1 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER1_EN +#define AM_HAL_PWRCTRL_IOM2 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER2_EN +#define AM_HAL_PWRCTRL_IOM3 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER3_EN +#define AM_HAL_PWRCTRL_IOM4 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER4_EN +#define AM_HAL_PWRCTRL_IOM5 AM_REG_PWRCTRL_DEVICEEN_IO_MASTER5_EN +#define AM_HAL_PWRCTRL_IOS AM_REG_PWRCTRL_DEVICEEN_IO_SLAVE_EN +#define AM_HAL_PWRCTRL_PDM AM_REG_PWRCTRL_DEVICEEN_PDM_EN +#define AM_HAL_PWRCTRL_UART0 AM_REG_PWRCTRL_DEVICEEN_UART0_EN +#define AM_HAL_PWRCTRL_UART1 AM_REG_PWRCTRL_DEVICEEN_UART1_EN + +//***************************************************************************** +// +// Macro to set the appropriate IOM peripheral when using +// am_hal_pwrctrl_periph_enable()/disable(). +// For Apollo2, the module argument must resolve to be a value from 0-5. +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_IOM(module) \ + (AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_EN << module) + +//***************************************************************************** +// +// Macro to set the appropriate UART peripheral when using +// am_hal_pwrctrl_periph_enable()/disable(). +// For Apollo2, the module argument must resolve to be a value from 0-1. +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_UART(module) \ + (AM_REG_PWRCTRL_DEVICEEN_UART0_EN << module) + + +//***************************************************************************** +// +// Memory enable values for am_hal_pwrctrl_memory_enable() +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_MEMEN_SRAM8K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM8K +#define AM_HAL_PWRCTRL_MEMEN_SRAM16K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM16K +#define AM_HAL_PWRCTRL_MEMEN_SRAM24K (AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM16K | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP0_SRAM2) +#define AM_HAL_PWRCTRL_MEMEN_SRAM32K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM32K +#define AM_HAL_PWRCTRL_MEMEN_SRAM64K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM64K +#define AM_HAL_PWRCTRL_MEMEN_SRAM96K \ + (AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM64K | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP2) +#define AM_HAL_PWRCTRL_MEMEN_SRAM128K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K +#define AM_HAL_PWRCTRL_MEMEN_SRAM160K \ + (AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP4) +#define AM_HAL_PWRCTRL_MEMEN_SRAM192K \ + (AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP4 | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP5) +#define AM_HAL_PWRCTRL_MEMEN_SRAM224K \ + (AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM128K | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP4 | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP5 | \ + AM_REG_PWRCTRL_MEMEN_SRAMEN_GROUP6) +#define AM_HAL_PWRCTRL_MEMEN_SRAM256K AM_REG_PWRCTRL_MEMEN_SRAMEN_SRAM256K + +#define AM_HAL_PWRCTRL_MEMEN_FLASH512K AM_REG_PWRCTRL_MEMEN_FLASH0_EN +#define AM_HAL_PWRCTRL_MEMEN_FLASH1M \ + (AM_REG_PWRCTRL_MEMEN_FLASH0_EN | \ + AM_REG_PWRCTRL_MEMEN_FLASH1_EN) +#define AM_HAL_PWRCTRL_MEMEN_CACHE \ + (AM_REG_PWRCTRL_MEMEN_CACHEB0_EN | \ + AM_REG_PWRCTRL_MEMEN_CACHEB2_EN) +#define AM_HAL_PWRCTRL_MEMEN_CACHE_DIS \ + ~(AM_REG_PWRCTRL_MEMEN_CACHEB0_EN | \ + AM_REG_PWRCTRL_MEMEN_CACHEB2_EN) + +// +// Power up all available memory devices (this is the default power up state) +// +#define AM_HAL_PWRCTRL_MEMEN_ALL \ + (AM_REG_PWRCTRL_MEMEN_SRAMEN_ALL | \ + AM_REG_PWRCTRL_MEMEN_FLASH0_EN | \ + AM_REG_PWRCTRL_MEMEN_FLASH1_EN | \ + AM_REG_PWRCTRL_MEMEN_CACHEB0_EN | \ + AM_REG_PWRCTRL_MEMEN_CACHEB2_EN) + +//***************************************************************************** +// +// Peripheral power enable and disable delays +// The delay counts are based on an internal clock that runs at half of +// HFRC. Therefore, we need to double the delay cycles. +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_DEVICEEN_DELAYCYCLES (22 * 2) +#define AM_HAL_PWRCTRL_DEVICEDIS_DELAYCYCLES (22 * 2) + +// +// Use the following only when enabling after sleep (not during initialization). +// +#define AM_HAL_PWRCTRL_BUCKEN_DELAYCYCLES (0 * 2) +#define AM_HAL_PWRCTRL_BUCKDIS_DELAYCYCLES (15 * 2) + +//***************************************************************************** +// +// Peripheral PWRONSTATUS groupings. +// +//***************************************************************************** +// +// Group DEVICEEN bits (per PWRONSTATUS groupings). +// +#define AM_HAL_PWRCTRL_DEVICEEN_IOM_0_2 \ + (AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_EN | \ + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER1_EN | \ + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER2_EN ) + +#define AM_HAL_PWRCTRL_DEVICEEN_IOM_3_5 \ + (AM_REG_PWRCTRL_DEVICEEN_IO_MASTER3_EN | \ + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER4_EN | \ + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER5_EN ) + +#define AM_HAL_PWRCTRL_DEVICEEN_IOS_UARTS \ + (AM_REG_PWRCTRL_DEVICEEN_UART0_EN | \ + AM_REG_PWRCTRL_DEVICEEN_UART1_EN | \ + AM_REG_PWRCTRL_DEVICEEN_IO_SLAVE_EN ) + +#define AM_HAL_PWRCTRL_DEVICEEN_ADC AM_REG_PWRCTRL_DEVICEEN_ADC_EN +#define AM_HAL_PWRCTRL_DEVICEEN_PDM AM_REG_PWRCTRL_DEVICEEN_PDM_EN + +// +// Map PWRONSTATUS bits to peripheral groupings. +// +#define AM_HAL_PWRCTRL_PWRONSTATUS_IOS_UARTS AM_REG_PWRCTRL_PWRONSTATUS_PDA_M +#define AM_HAL_PWRCTRL_PWRONSTATUS_IOM_3_5 AM_REG_PWRCTRL_PWRONSTATUS_PDC_M +#define AM_HAL_PWRCTRL_PWRONSTATUS_IOM_0_2 AM_REG_PWRCTRL_PWRONSTATUS_PDB_M +#define AM_HAL_PWRCTRL_PWRONSTATUS_ADC AM_REG_PWRCTRL_PWRONSTATUS_PDADC_M +#define AM_HAL_PWRCTRL_PWRONSTATUS_PDM AM_REG_PWRCTRL_PWRONSTATUS_PD_PDM_M + +#define POLL_PWRSTATUS(ui32Peripheral) \ + if ( 1 ) \ + { \ + uint32_t ui32PwrOnStat; \ + if ( ui32Peripheral & AM_HAL_PWRCTRL_DEVICEEN_IOM_0_2 ) \ + { \ + ui32PwrOnStat = AM_HAL_PWRCTRL_PWRONSTATUS_IOM_0_2; \ + } \ + else if ( ui32Peripheral & AM_HAL_PWRCTRL_DEVICEEN_IOM_3_5 ) \ + { \ + ui32PwrOnStat = AM_HAL_PWRCTRL_PWRONSTATUS_IOM_3_5; \ + } \ + else if ( ui32Peripheral & AM_HAL_PWRCTRL_DEVICEEN_IOS_UARTS ) \ + { \ + ui32PwrOnStat = AM_HAL_PWRCTRL_PWRONSTATUS_IOS_UARTS; \ + } \ + else if ( ui32Peripheral & AM_HAL_PWRCTRL_DEVICEEN_ADC ) \ + { \ + ui32PwrOnStat = AM_HAL_PWRCTRL_PWRONSTATUS_ADC; \ + } \ + else if ( ui32Peripheral & AM_HAL_PWRCTRL_DEVICEEN_PDM ) \ + { \ + ui32PwrOnStat = AM_HAL_PWRCTRL_PWRONSTATUS_PDM; \ + } \ + else \ + { \ + ui32PwrOnStat = 0xFFFFFFFF; \ + } \ + \ + /* */ \ + /* Wait for the power control setting to take effect. */ \ + /* */ \ + while ( !(AM_REG(PWRCTRL, PWRONSTATUS) & ui32PwrOnStat) ); \ + } + +//***************************************************************************** +// +// Memory PWRONSTATUS enable values for am_hal_pwrctrl_memory_enable() +// +//***************************************************************************** +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_8K \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_16K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_24K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_32K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_64K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_96K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_128K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP3_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_160K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP4_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP3_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_192K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP5_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP4_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP3_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_224K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP6_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP5_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP4_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP3_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_256K \ + (AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP7_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP6_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP5_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP4_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP3_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP2_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP1_SRAM_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM3_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM2_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM1_M | \ + AM_REG_PWRCTRL_PWRONSTATUS_PD_GRP0_SRAM0_M) + +#define AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_ALL \ + AM_HAL_PWRCTRL_PWRONSTATUS_SRAM_256K + +//***************************************************************************** +// +// Function prototypes +// +//***************************************************************************** +extern void am_hal_pwrctrl_periph_enable(uint32_t ui32Peripheral); +extern void am_hal_pwrctrl_periph_disable(uint32_t ui32Peripheral); +extern bool am_hal_pwrctrl_memory_enable(uint32_t ui32MemEn); +extern void am_hal_pwrctrl_bucks_init(void); +extern void am_hal_pwrctrl_bucks_enable(void); +extern void am_hal_pwrctrl_bucks_disable(void); +extern void am_hal_pwrctrl_low_power_init(void); + +#endif // AM_HAL_PWRCTRL_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_queue.c b/bsp/apollo2/libraries/drivers/hal/am_hal_queue.c new file mode 100644 index 0000000000..66a9846c29 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_queue.c @@ -0,0 +1,286 @@ +//***************************************************************************** +// +// am_hal_queue.c +//! @file +//! +//! @brief Functions for implementing a queue system. +//! +//! @addtogroup Miscellaneous2 Software Features (MISC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Initializes a queue. +//! +//! @param psQueue - Pointer to a queue structure. +//! @param pvData - Pointer to a memory location to be used for data storage. +//! @param ui32ItemSize - Number of bytes per item in the queue. +//! @param ui32ArraySize - Number of bytes in the data array. +//! +//! This function initializes the members of a queue structure and attaches it +//! to an array of memory that it can use for storage. This function should be +//! called before the queue is used. +//! +//! In this example, we are creating a queue that can hold 1024 32-bit +//! integers. The integers themselves will be stored in the array named +//! pui32WorkingSpace, while information about the queue itself will be stored +//! in sDataQueue. +//! +//! @note The caller should not modify any of the members of am_hal_queue_t +//! structures. The queue API will handle these members in a thread-safe way. +//! +//! @note The queue will remember what size data is in it. Other queue API +//! functions will perform transfers in units of "items" where one "item" is +//! the number of bytes you specify in the \e ui32ItemSize argument upon +//! initialization. +//! +//! Example usage: +//! +//! @code +//! +//! // +//! // Declare a queue structure and an array of bytes we can use to store +//! // data. +//! // +//! am_hal_queue_t sDataQueue; +//! uint32_t pui32WorkingSpace[1024]; +//! +//! // +//! // Attach the queue structure to the working memory. +//! // +//! am_hal_queue_init(&sDataQueue, pui8WorkingSpace, sizeof(uint32_t) +//! sizeof(pui32WorkingSpace)); +//! +//! @endcode +//! +//! The am_hal_queue_from_array macro is a convenient shorthand for this +//! operation. The code below does the same thing as the code above. +//! +//! @code +//! +//! // +//! // Declare a queue structure and an array of bytes we can use to store +//! // data. +//! // +//! am_hal_queue_t sDataQueue; +//! uint32_t pui32WorkingSpace[1024]; +//! +//! // +//! // Attach the queue structure to the working memory. +//! // +//! am_hal_queue_from_array(&sDataQueue, pui8WorkingSpace); +//! +//! @endcode +// +//***************************************************************************** +void +am_hal_queue_init(am_hal_queue_t *psQueue, void *pvData, uint32_t ui32ItemSize, + uint32_t ui32ArraySize) +{ + psQueue->ui32WriteIndex = 0; + psQueue->ui32ReadIndex = 0; + psQueue->ui32Length = 0; + psQueue->ui32Capacity = ui32ArraySize; + psQueue->ui32ItemSize = ui32ItemSize; + psQueue->pui8Data = (uint8_t *) pvData; +} + +//***************************************************************************** +// +//! @brief Adds an item to the Queue +//! +//! @param psQueue - Pointer to a queue structure. +//! @param pvSource - Pointer to the data to be added. +//! @param ui32NumItems - Number of items to be added. +//! +//! This function will copy the data pointed to by pvSource into the queue. The +//! \e ui32NumItems term specifies the number of items to be copied from \e +//! pvSource. The size of an "item" depends on how the queue was initialized. +//! Please see am_hal_queue_init() for more information on this. +//! +//! @return true if the add operation was successful, or false if the queue +//! didn't have enough space. +// +//***************************************************************************** +bool +am_hal_queue_item_add(am_hal_queue_t *psQueue, const void *pvSource, uint32_t ui32NumItems) +{ + uint32_t i; + uint8_t *pui8Source; + uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize; + bool bSuccess = false; + uint32_t ui32Primask; + + pui8Source = (uint8_t *) pvSource; + + ui32Primask = am_hal_interrupt_master_disable(); + + // + // Check to make sure that the buffer isn't already full + // + if ( am_hal_queue_space_left(psQueue) >= ui32Bytes ) + { + // + // Loop over the bytes in the source array. + // + for ( i = 0; i < ui32Bytes; i++ ) + { + // + // Write the value to the buffer. + // + psQueue->pui8Data[psQueue->ui32WriteIndex] = pui8Source[i]; + + // + // Advance the write index, making sure to wrap if necessary. + // + psQueue->ui32WriteIndex = ((psQueue->ui32WriteIndex + 1) % + psQueue->ui32Capacity); + } + + // + // Update the length value appropriately. + // + psQueue->ui32Length += ui32Bytes; + + // + // Report a success. + // + bSuccess = true; + } + else + { + // + // The buffer can't fit the amount of data requested. Return a + // failure. + // + bSuccess = false; + } + + am_hal_interrupt_master_set(ui32Primask); + + return bSuccess; +} + +//***************************************************************************** +// +//! @brief Removes an item from the Queue +//! +//! @param psQueue - Pointer to a queue structure. +//! @param pvDest - Pointer to the data to be added. +//! @param ui32NumItems - Number of items to be added. +//! +//! This function will copy the data from the queue into the memory pointed to +//! by pvDest. The \e ui32NumItems term specifies the number of items to be +//! copied from the queue. The size of an "item" depends on how the queue was +//! initialized. Please see am_hal_queue_init() for more information on this. +//! +//! @return true if we were able to pull the requested number of items from the +//! queue, or false if the queue didn't have that many items to pull. +// +//***************************************************************************** +bool +am_hal_queue_item_get(am_hal_queue_t *psQueue, void *pvDest, uint32_t ui32NumItems) +{ + uint32_t i; + uint8_t *pui8Dest; + uint32_t ui32Bytes = ui32NumItems * psQueue->ui32ItemSize; + bool bSuccess = false; + uint32_t ui32Primask; + + pui8Dest = (uint8_t *) pvDest; + + ui32Primask = am_hal_interrupt_master_disable(); + + // + // Check to make sure that the buffer isn't empty + // + if ( am_hal_queue_data_left(psQueue) >= ui32Bytes ) + { + // + // Loop over the bytes in the destination array. + // + for ( i = 0; i < ui32Bytes; i++ ) + { + // + // Grab the next value from the buffer. + // + pui8Dest[i] = psQueue->pui8Data[psQueue->ui32ReadIndex]; + + // + // Advance the read index, wrapping if needed. + // + psQueue->ui32ReadIndex = ((psQueue->ui32ReadIndex + 1) % + psQueue->ui32Capacity); + } + + // + // Adjust the length value to reflect the change. + // + psQueue->ui32Length -= ui32Bytes; + + // + // Report a success. + // + bSuccess = true; + } + else + { + // + // If the buffer didn't have enough data, just return false. + // + bSuccess = false; + } + + am_hal_interrupt_master_set(ui32Primask); + + return bSuccess; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_queue.h b/bsp/apollo2/libraries/drivers/hal/am_hal_queue.h new file mode 100644 index 0000000000..11e8ace90a --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_queue.h @@ -0,0 +1,123 @@ +//***************************************************************************** +// +// am_hal_queue.h +//! @file +//! +//! @brief Functions for implementing a queue system. +//! +//! @addtogroup Miscellaneous2 Software Features (MISC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_QUEUE_H +#define AM_HAL_QUEUE_H + +//***************************************************************************** +// +//! @brief A data structure that will operate as a queue. +//! +//! This data structure holds information necessary for operating a thread-safe +//! queue. When declaring a structure of type am_hal_queue_t, you will also need +//! to provide some working memory for the queue to use. For more information on +//! setting up and using the am_hal_queue_t structure, please see the +//! documentation for am_hal_queue_init(). +// +//***************************************************************************** +typedef struct +{ + uint32_t ui32WriteIndex; + uint32_t ui32ReadIndex; + uint32_t ui32Length; + uint32_t ui32Capacity; + uint32_t ui32ItemSize; + uint8_t *pui8Data; +} +am_hal_queue_t; + +//***************************************************************************** +// +// Function-like macros. +// +//***************************************************************************** +#define am_hal_queue_empty(psQueue) \ + ((psQueue)->ui32Length == 0) + +#define am_hal_queue_full(psQueue) \ + ((psQueue)->ui32Length == (psQueue)->ui32Capacity) + +#define am_hal_queue_space_left(psQueue) \ + ((psQueue)->ui32Capacity - (psQueue)->ui32Length) + +#define am_hal_queue_data_left(psQueue) \ + ((psQueue)->ui32Length) + +//***************************************************************************** +// +// Use this to make sure you get the size parameters right. +// +//***************************************************************************** +#define am_hal_queue_from_array(queue, array) \ + am_hal_queue_init((queue), (array), sizeof((array)[0]), sizeof(array)) + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// External function definitions. +// +//***************************************************************************** +extern void am_hal_queue_init(am_hal_queue_t *psQueue, void *pvData, uint32_t ui32ItemSize, uint32_t ui32ArraySize); +extern bool am_hal_queue_item_add(am_hal_queue_t *psQueue, const void *pvSource, uint32_t ui32NumItems); +extern bool am_hal_queue_item_get(am_hal_queue_t *psQueue, void *pvDest, uint32_t ui32NumItems); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_QUEUE_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_reset.c b/bsp/apollo2/libraries/drivers/hal/am_hal_reset.c new file mode 100644 index 0000000000..86d5cf10b7 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_reset.c @@ -0,0 +1,160 @@ +//***************************************************************************** +// +// am_hal_reset.c +//! @file +//! +//! @brief Hardware abstraction layer for the Reset Generator module. +//! +//! @addtogroup rstgen2 Reset Generator (RSTGEN) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Configure the Reset Generator. +//! +//! @param ui32Config - Or together the supplied macros to enable +//! configurations to obtain the desired reset generator settings. +//! +//! This function will set the reset generator's configuration register based on +//! the user's desired settings listed in the supplied arugment. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_reset_init(uint32_t ui32Config) +{ + // + // Write the configuration to the reset generator + // + AM_REG(RSTGEN, CFG) = ui32Config; +} + +//***************************************************************************** +// +//! @brief Issue a POR (Apollo's last stage interrupt). +//! +//! This function will issue a POR reset. +//! The Apollo chip has numerous stages of reset. POR is the last and is also +//! the reset invoked by the chip's reset pin, the watchdog timer, the AIRCR +//! reset, and the SWD debugger requested interrupt. +//! +//! The Debug Access Port in the M4 is not cleared by this reset. +//! +//! @return None. +// +//***************************************************************************** +void am_hal_reset_por(void) +{ + // + // Write the POR key to the software POR register. + // + AM_REG(RSTGEN, SWPOR) = + AM_REG_RSTGEN_SWPOR_SWPORKEY(AM_REG_RSTGEN_SWPOR_SWPORKEY_KEYVALUE); +} + +//***************************************************************************** +// +//! @brief Issue a POI (Apollo's second stage interrupt). +//! +//! This function will issue a POI reset. +//! The Apollo chip has numerous stages of reset. POI is the second stage. +//! A few modules are reset by POI that are not reset by POR, notably POI +//! causes the shadow registers to be reloaded from the OTP. A full power +//! cycle or POI should be used after writing new flash, debug or SRAM +//! protection bits into the OTP for these protections to take effect. +//! +//! The Debug Access Port in the M4 is not cleared by this reset. +//! +//! @return None. +// +//***************************************************************************** +void am_hal_reset_poi(void) +{ + // + // Write the POI key to the software POI register. + // + AM_REG(RSTGEN, SWPOI) = + AM_REG_RSTGEN_SWPOI_SWPOIKEY(AM_REG_RSTGEN_SWPOI_SWPOIKEY_KEYVALUE); +} + +//***************************************************************************** +// +//! @brief Retrieve the status bits from the reset generator. +//! +//! This function will get the status bits from the reset generator. +//! These bits are sticky and show the accumulation of reset types that the +//! Apollo chip has experienced since power on. One should clear these out +//! after reading them. +//! +//! @return None. +// +//***************************************************************************** +uint32_t am_hal_reset_status_get(void) +{ + // + // Retrieve the reset generator status bits + // + return AM_REG(RSTGEN, STAT); +} + +//***************************************************************************** +// +//! @brief Clear ALL of the status bits in the reset generator. +//! +//! This function will clear all status bits in the reset generator status. +//! +//! @return None. +// +//***************************************************************************** +void am_hal_reset_status_clear(void) +{ + AM_REG(RSTGEN, CLRSTAT) = AM_REG_RSTGEN_CLRSTAT_CLRSTAT(1); +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_reset.h b/bsp/apollo2/libraries/drivers/hal/am_hal_reset.h new file mode 100644 index 0000000000..a3273dad10 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_reset.h @@ -0,0 +1,119 @@ +//***************************************************************************** +// +// am_hal_reset.h +//! @file +//! +//! @brief Hardware abstraction layer for the Reset Generator module. +//! +//! @addtogroup wdt2 Watchdog Timer (RSTGEN) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_RSTGEN_H +#define AM_HAL_RSTGEN_H + +//***************************************************************************** +// +//! @name Reset Generator Configuration +//! @brief These macros may be used to set the reset generator's configuration. +//! @{ +// +//***************************************************************************** +#define AM_HAL_RESET_CFG_WDT_RESET_ENABLE (AM_REG_RSTGEN_CFG_WDREN(1)) +// Brown out high (2.1v) reset enable. +#define AM_HAL_RESET_CFG_BOD_HIGH_RESET_ENABLE (AM_REG_RSTGEN_CFG_BODHREN(1)) +//! @} + +//***************************************************************************** +// +//! @name Reset Generator Status Bit Masks +//! @brief These macros may be used to determine which type(s) of resets have +//! been seen. +//! @{ +// +//***************************************************************************** +// Reset was initiated by a Watchdog Timer Reset. +#define AM_HAL_RESET_STAT_WDT (AM_REG_RSTGEN_STAT_WDRSTAT_M) + +// Reset was a initiated by Debugger Reset. +#define AM_HAL_RESET_STAT_DEBUG (AM_REG_RSTGEN_STAT_DBGRSTAT_M) + +// Reset was a initiated by Software POI Reset. +#define AM_HAL_RESET_STAT_POI (AM_REG_RSTGEN_STAT_POIRSTAT_M) + +// Reset was a initiated by Software POR or AIRCR Reset. +#define AM_HAL_RESET_STAT_SOFTWARE (AM_REG_RSTGEN_STAT_SWRSTAT_M) + +// Reset was initiated by a Brown-Out Reset. +#define AM_HAL_RESET_STAT_BOD (AM_REG_RSTGEN_STAT_BORSTAT_M) + +// Reset was initiated by a Power Cycle +#define AM_HAL_RESET_STAT_POWER_CYCLE (AM_REG_RSTGEN_STAT_PORSTAT_M) + +// Reset was initiated by an External Reset. +#define AM_HAL_RESET_STAT_EXTERNAL (AM_REG_RSTGEN_STAT_EXRSTAT_M) +//! @} + +#ifdef __cplusplus +extern "C" +{ +#endif +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_reset_init(uint32_t ui32Config); +extern void am_hal_reset_por(void); +extern void am_hal_reset_poi(void); +extern uint32_t am_hal_reset_status_get(void); +extern void am_hal_reset_status_clear(void); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_RSTGEN_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.c b/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.c new file mode 100644 index 0000000000..4630d5a117 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.c @@ -0,0 +1,678 @@ +//***************************************************************************** +// +// am_hal_rtc.c +//! @file +//! +//! @brief Functions for interfacing with the Real-Time Clock (RTC). +//! +//! @addtogroup rtc2 Real-Time Clock (RTC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Converts a Binary Coded Decimal (BCD) byte to its Decimal form. +// +//***************************************************************************** +static uint8_t +bcd_to_dec(uint8_t ui8BCDByte) +{ + return (((ui8BCDByte & 0xF0) >> 4) * 10) + (ui8BCDByte & 0x0F); +} + +//***************************************************************************** +// +// Converts a Decimal byte to its Binary Coded Decimal (BCD) form. +// +//***************************************************************************** +static uint8_t +dec_to_bcd(uint8_t ui8DecimalByte) +{ + return (((ui8DecimalByte / 10) << 4) | (ui8DecimalByte % 10)); +} + +//***************************************************************************** +// +//! @brief Selects the clock source for the RTC. +//! +//! @param ui32OSC the clock source for the RTC. +//! +//! This function selects the clock source for the RTC. +//! +//! Valid values for ui32OSC are: +//! +//! AM_HAL_RTC_OSC_LFRC +//! AM_HAL_RTC_OSC_XT +//! +//! @return None +// +//***************************************************************************** +void +am_hal_rtc_osc_select(uint32_t ui32OSC) +{ + // + // Set XT if flag is set. + // Otherwise configure for LFRC. + // + if (ui32OSC) + { + AM_REG(CLKGEN, OCTRL) |= AM_REG_CLKGEN_OCTRL_OSEL_M; + } + else + { + AM_REG(CLKGEN, OCTRL) &= ~AM_REG_CLKGEN_OCTRL_OSEL_M; + } +} + +//***************************************************************************** +// +//! @brief Enable/Start the RTC oscillator. +//! +//! Starts the RTC oscillator. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_osc_enable(void) +{ + // + // Start the RTC Oscillator. + // + AM_REG(RTC, RTCCTL) &= ~AM_REG_RTC_RTCCTL_RSTOP(1); +} + +//***************************************************************************** +// +//! @brief Disable/Stop the RTC oscillator. +//! +//! Stops the RTC oscillator. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_osc_disable(void) +{ + // + // Stop the RTC Oscillator. + // + AM_REG(RTC, RTCCTL) |= AM_REG_RTC_RTCCTL_RSTOP(1); +} + +//***************************************************************************** +// +//! @brief Configures the RTC for 12 or 24 hour time keeping. +//! +//! @param b12Hour - A 'true' configures the RTC for 12 hour time keeping. +//! +//! Configures the RTC for 12 (true) or 24 (false) hour time keeping. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_time_12hour(bool b12Hour) +{ + // + // Set the 12/24 hour bit. + // + AM_REG(RTC, RTCCTL) |= AM_REG_RTC_RTCCTL_HR1224(b12Hour); +} + +//***************************************************************************** +// +//! @brief Enable selected RTC interrupts. +//! +//! @param ui32Interrupt - desired interrupts +//! +//! Enables the RTC interrupts. +//! +//! ui32Interrupt should be an OR of the following: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_int_enable(uint32_t ui32Interrupt) +{ + // + // Enable the interrupts. + // + AM_REG(RTC, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return the enabled RTC interrupts. +//! +//! Returns the enabled RTC interrupts. +//! +//! @return enabled RTC interrupts. Return is a logical or of: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +// +//***************************************************************************** +uint32_t +am_hal_rtc_int_enable_get(void) +{ + // + // Read the RTC interrupt enable register, and return its contents. + // + return AM_REG(RTC, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable selected RTC interrupts. +//! +//! @param ui32Interrupt - desired interrupts +//! +//! Disables the RTC interrupts. +//! +//! ui32Interrupt should be an OR of the following: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_int_disable(uint32_t ui32Interrupt) +{ + // + // Disable the interrupts. + // + AM_REG(RTC, INTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Sets the selected RTC interrupts. +//! +//! @param ui32Interrupt - desired interrupts +//! +//! Sets the RTC interrupts causing them to immediately trigger. +//! +//! ui32Interrupt should be an OR of the following: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_int_set(uint32_t ui32Interrupt) +{ + // + // Set the interrupts. + // + AM_REG(RTC, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Clear selected RTC interrupts. +//! +//! @param ui32Interrupt - desired interrupts +//! +//! Clears the RTC interrupts. +//! +//! ui32Interrupt should be an OR of the following: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_int_clear(uint32_t ui32Interrupt) +{ + // + // Clear the interrupts. + // + AM_REG(RTC, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Returns the RTC interrupt status. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! Returns the RTC interrupt status. +//! +//! @return Bitwise representation of the current interrupt status. +//! +//! The return value will be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_RTC_INT_ALM +//! AM_HAL_RTC_INT_OF +//! AM_HAL_RTC_INT_ACC +//! AM_HAL_RTC_INT_ACF +// +//***************************************************************************** +uint32_t +am_hal_rtc_int_status_get(bool bEnabledOnly) +{ + // + // Get the interrupt status. + // + if (bEnabledOnly) + { + uint32_t u32RetVal; + u32RetVal = AM_REG(RTC, INTSTAT); + u32RetVal &= AM_REG(RTC, INTEN); + return u32RetVal & + (AM_HAL_RTC_INT_ALM | AM_HAL_RTC_INT_OF | + AM_HAL_RTC_INT_ACC | AM_HAL_RTC_INT_ACF); + } + else + { + return (AM_REG(RTC, INTSTAT) & (AM_HAL_RTC_INT_ALM | + AM_HAL_RTC_INT_OF | + AM_HAL_RTC_INT_ACC | + AM_HAL_RTC_INT_ACF)); + } +} + +//***************************************************************************** +// +//! @brief Set the Real Time Clock counter registers. +//! +//! @param *pTime - A pointer to the time structure. +//! +//! Sets the RTC counter registers to the supplied values. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_time_set(am_hal_rtc_time_t *pTime) +{ + // + // Enable writing to the counters. + // + AM_REG(RTC, RTCCTL) |= AM_REG_RTC_RTCCTL_WRTC(1); + + // + // Write the RTCLOW register. + // + AM_REG(RTC, CTRLOW) = + AM_REG_RTC_CTRLOW_CTRHR(dec_to_bcd(pTime->ui32Hour)) | + AM_REG_RTC_CTRLOW_CTRMIN(dec_to_bcd(pTime->ui32Minute)) | + AM_REG_RTC_CTRLOW_CTRSEC(dec_to_bcd(pTime->ui32Second)) | + AM_REG_RTC_CTRLOW_CTR100(dec_to_bcd(pTime->ui32Hundredths)); + + // + // Write the RTCUP register. + // + AM_REG(RTC, CTRUP) = + AM_REG_RTC_CTRUP_CEB((pTime->ui32CenturyEnable)) | + AM_REG_RTC_CTRUP_CB((pTime->ui32Century)) | + AM_REG_RTC_CTRUP_CTRWKDY((pTime->ui32Weekday)) | + AM_REG_RTC_CTRUP_CTRYR(dec_to_bcd((pTime->ui32Year))) | + AM_REG_RTC_CTRUP_CTRMO(dec_to_bcd((pTime->ui32Month))) | + AM_REG_RTC_CTRUP_CTRDATE(dec_to_bcd((pTime->ui32DayOfMonth))); + + // + // Disable writing to the counters. + // + AM_REG(RTC, RTCCTL) |= AM_REG_RTC_RTCCTL_WRTC(0); +} + +//***************************************************************************** +// +//! @brief Get the Real Time Clock current time. +//! +//! @param *pTime - A pointer to the time structure to store the current time. +//! +//! Gets the RTC's current time +//! +//! @return 0 for success and 1 for error. +// +//***************************************************************************** +uint32_t +am_hal_rtc_time_get(am_hal_rtc_time_t *pTime) +{ + uint32_t ui32RTCLow, ui32RTCUp, ui32Value; + + // + // Read the upper and lower RTC registers. + // + ui32RTCLow = AM_REG(RTC, CTRLOW); + ui32RTCUp = AM_REG(RTC, CTRUP); + + // + // Break out the lower word. + // + ui32Value = + ((ui32RTCLow & AM_REG_RTC_CTRLOW_CTRHR_M) >> AM_REG_RTC_CTRLOW_CTRHR_S); + pTime->ui32Hour = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCLow & AM_REG_RTC_CTRLOW_CTRMIN_M) >> AM_REG_RTC_CTRLOW_CTRMIN_S); + pTime->ui32Minute = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCLow & AM_REG_RTC_CTRLOW_CTRSEC_M) >> AM_REG_RTC_CTRLOW_CTRSEC_S); + pTime->ui32Second = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCLow & AM_REG_RTC_CTRLOW_CTR100_M) >> AM_REG_RTC_CTRLOW_CTR100_S); + pTime->ui32Hundredths = bcd_to_dec(ui32Value); + + // + // Break out the upper word. + // + pTime->ui32ReadError = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CTERR_M) >> AM_REG_RTC_CTRUP_CTERR_S); + + pTime->ui32CenturyEnable = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CEB_M) >> AM_REG_RTC_CTRUP_CEB_S); + + pTime->ui32Century = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CB_M) >> AM_REG_RTC_CTRUP_CB_S); + + ui32Value = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CTRWKDY_M) >> AM_REG_RTC_CTRUP_CTRWKDY_S); + pTime->ui32Weekday = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CTRYR_M) >> AM_REG_RTC_CTRUP_CTRYR_S); + pTime->ui32Year = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CTRMO_M) >> AM_REG_RTC_CTRUP_CTRMO_S); + pTime->ui32Month = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32RTCUp & AM_REG_RTC_CTRUP_CTRDATE_M) >> AM_REG_RTC_CTRUP_CTRDATE_S); + pTime->ui32DayOfMonth = bcd_to_dec(ui32Value); + + // + // Was there a read error? + // + if (pTime->ui32ReadError) + { + return 1; + } + else + { + return 0; + } +} + +//***************************************************************************** +// +//! @brief Sets the alarm repeat interval. +//! +//! @param ui32RepeatInterval the desired repeat interval. +//! +//! Sets the alarm repeat interval. +//! +//! Valid values for ui32RepeatInterval: +//! +//! AM_HAL_RTC_ALM_RPT_DIS +//! AM_HAL_RTC_ALM_RPT_YR +//! AM_HAL_RTC_ALM_RPT_MTH +//! AM_HAL_RTC_ALM_RPT_WK +//! AM_HAL_RTC_ALM_RPT_DAY +//! AM_HAL_RTC_ALM_RPT_HR +//! AM_HAL_RTC_ALM_RPT_MIN +//! AM_HAL_RTC_ALM_RPT_SEC +//! AM_HAL_RTC_ALM_RPT_10TH +//! AM_HAL_RTC_ALM_RPT_100TH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_alarm_interval_set(uint32_t ui32RepeatInterval) +{ + uint32_t ui32RptInt, ui32Alm100, ui32Value; + + switch(ui32RepeatInterval) + { + // + // If repeat every 10th set RPT and ALM100 field accordinly + // + case AM_HAL_RTC_ALM_RPT_10TH: + ui32RptInt = AM_HAL_RTC_ALM_RPT_SEC; + ui32Alm100 = AM_HAL_RTC_ALM100_10TH; + break; + // + // If repeat every 100th set RPT and ALM100 field accordinly + // + case AM_HAL_RTC_ALM_RPT_100TH: + ui32RptInt = AM_HAL_RTC_ALM_RPT_SEC; + ui32Alm100 = AM_HAL_RTC_ALM100_100TH; + break; + // + // Otherwise set RPT as value passed. ALM100 values need to be 0xnn + // in this setting where n = 0-9. + // + default: + // + // Get the current value of the ALM100 field. + // + ui32Value = AM_BFR(RTC, ALMLOW, ALM100); + + // + // If ALM100 was previous EVERY_10TH or EVERY_100TH reset to zero + // otherwise keep previous setting. + // + ui32Alm100 = ui32Value >= 0xF0 ? 0 : ui32Value; + + // + // Set RPT value to value passed. + // + ui32RptInt = ui32RepeatInterval; + break; + } + + // + // Write the interval to the register. + // + AM_BFW(RTC, RTCCTL, RPT, ui32RptInt); + + // + // Write the Alarm 100 bits in the ALM100 register. + // + AM_BFW(RTC, ALMLOW, ALM100, ui32Alm100); +} + +//***************************************************************************** +// +//! @brief Sets the RTC's Alarm. +//! +//! @param *pTime - A pointer to the time structure. +//! @param ui32RepeatInterval - the desired alarm repeat interval. +//! +//! Set the Real Time Clock Alarm Parameters. +//! +//! Valid values for ui32RepeatInterval: +//! +//! AM_HAL_RTC_ALM_RPT_DIS +//! AM_HAL_RTC_ALM_RPT_YR +//! AM_HAL_RTC_ALM_RPT_MTH +//! AM_HAL_RTC_ALM_RPT_WK +//! AM_HAL_RTC_ALM_RPT_DAY +//! AM_HAL_RTC_ALM_RPT_HR +//! AM_HAL_RTC_ALM_RPT_MIN +//! AM_HAL_RTC_ALM_RPT_SEC +//! AM_HAL_RTC_ALM_RPT_10TH +//! AM_HAL_RTC_ALM_RPT_EVERY_100TH +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_alarm_set(am_hal_rtc_time_t *pTime, uint32_t ui32RepeatInterval) +{ + uint8_t ui8Value = 0; + + // + // Write the interval to the register. + // + AM_REG(RTC, RTCCTL) |= + AM_REG_RTC_RTCCTL_RPT(ui32RepeatInterval > 0x7 ? 0x7 : ui32RepeatInterval); + + // + // Check if the interval is 10th or every 100th and track it in ui8Value. + // + if (ui32RepeatInterval == AM_HAL_RTC_ALM_RPT_10TH) + { + ui8Value = 0xF0; + } + else if (ui32RepeatInterval == AM_HAL_RTC_ALM_RPT_100TH) + { + ui8Value = 0xFF; + } + + // + // Write the ALMUP register. + // + AM_REG(RTC, ALMUP) = + AM_REG_RTC_ALMUP_ALMWKDY((pTime->ui32Weekday)) | + AM_REG_RTC_ALMUP_ALMMO(dec_to_bcd((pTime->ui32Month))) | + AM_REG_RTC_ALMUP_ALMDATE(dec_to_bcd((pTime->ui32DayOfMonth))); + + // + // Write the ALMLOW register. + // + AM_REG(RTC, ALMLOW) = + AM_REG_RTC_ALMLOW_ALMHR(dec_to_bcd(pTime->ui32Hour)) | + AM_REG_RTC_ALMLOW_ALMMIN(dec_to_bcd(pTime->ui32Minute)) | + AM_REG_RTC_ALMLOW_ALMSEC(dec_to_bcd(pTime->ui32Second)) | + AM_REG_RTC_ALMLOW_ALM100(dec_to_bcd(pTime->ui32Hundredths) | ui8Value); +} + +//***************************************************************************** +// +//! @brief Get the Real Time Clock Alarm Parameters +//! +//! @param *pTime - A pointer to the time structure to store the current alarm. +//! +//! Gets the RTC's Alarm time +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_rtc_alarm_get(am_hal_rtc_time_t *pTime) +{ + uint32_t ui32ALMLow, ui32ALMUp, ui32Value; + + // + // Read the upper and lower RTC registers. + // + ui32ALMLow = AM_REG(RTC, ALMLOW); + ui32ALMUp = AM_REG(RTC, ALMUP); + + // + // Break out the lower word. + // + ui32Value = + ((ui32ALMLow & AM_REG_RTC_ALMLOW_ALMHR_M) >> AM_REG_RTC_ALMLOW_ALMHR_S); + pTime->ui32Hour = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32ALMLow & AM_REG_RTC_ALMLOW_ALMMIN_M) >> AM_REG_RTC_ALMLOW_ALMMIN_S); + pTime->ui32Minute = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32ALMLow & AM_REG_RTC_ALMLOW_ALMSEC_M) >> AM_REG_RTC_ALMLOW_ALMSEC_S); + pTime->ui32Second = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32ALMLow & AM_REG_RTC_ALMLOW_ALM100_M) >> AM_REG_RTC_ALMLOW_ALM100_S); + pTime->ui32Hundredths = bcd_to_dec(ui32Value); + + // + // Break out the upper word. + // + pTime->ui32ReadError = 0; + pTime->ui32CenturyEnable = 0; + pTime->ui32Century = 0; + + ui32Value = + ((ui32ALMUp & AM_REG_RTC_ALMUP_ALMWKDY_M) >> AM_REG_RTC_ALMUP_ALMWKDY_S); + pTime->ui32Weekday = bcd_to_dec(ui32Value); + + pTime->ui32Year = 0; + + ui32Value = + ((ui32ALMUp & AM_REG_RTC_ALMUP_ALMMO_M) >> AM_REG_RTC_ALMUP_ALMMO_S); + pTime->ui32Month = bcd_to_dec(ui32Value); + + ui32Value = + ((ui32ALMUp & AM_REG_RTC_ALMUP_ALMDATE_M) >> AM_REG_RTC_ALMUP_ALMDATE_S); + pTime->ui32DayOfMonth = bcd_to_dec(ui32Value); +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.h b/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.h new file mode 100644 index 0000000000..9304a6c67f --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_rtc.h @@ -0,0 +1,185 @@ +//***************************************************************************** +// +// am_hal_rtc.h +//! @file +//! +//! @brief Functions for interfacing and accessing the Real-Time Clock (RTC). +//! +//! @addtogroup rtc2 Real-Time Clock (RTC) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_RTC_H +#define AM_HAL_RTC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name OSC Start and Stop +//! @brief OSC Start and Stop defines. +//! +//! OSC Start and Stop defines to be used with \e am_hal_clkgen_osc_x(). +//! @{ +// +//***************************************************************************** +#define AM_HAL_RTC_OSC_LFRC 0x1 +#define AM_HAL_RTC_OSC_XT 0x0 +//! @} + +//***************************************************************************** +// +//! @name RTC Interrupts +//! @brief Macro definitions for RTC interrupt status bits. +//! +//! These macros correspond to the bits in the RTC interrupt status register. +//! They may be used with any of the \e am_hal_rtc_int_x() functions. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_RTC_INT_ALM AM_REG_RTC_INTEN_ALM_M +#define AM_HAL_RTC_INT_OF AM_REG_RTC_INTEN_OF_M +#define AM_HAL_RTC_INT_ACC AM_REG_RTC_INTEN_ACC_M +#define AM_HAL_RTC_INT_ACF AM_REG_RTC_INTEN_ACF_M +//! @} + +//***************************************************************************** +// +//! @name RTC Alarm Repeat Interval. +//! @brief Macro definitions for the RTC alarm repeat interval. +//! +//! These macros correspond to the RPT bits in the RTCCTL register. +//! They may be used with the \e am_hal_rtc_alarm_interval_set() function. +//! +//! Note: AM_HAL_RTC_ALM_RPT_10TH and AM_HAL_RTC_ALM_RPT_100TH do not +//! correspond to the RPT bits but are used in conjunction with setting the +//! ALM100 bits in the ALMLOW register. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_RTC_ALM_RPT_DIS 0x0 +#define AM_HAL_RTC_ALM_RPT_YR 0x1 +#define AM_HAL_RTC_ALM_RPT_MTH 0x2 +#define AM_HAL_RTC_ALM_RPT_WK 0x3 +#define AM_HAL_RTC_ALM_RPT_DAY 0x4 +#define AM_HAL_RTC_ALM_RPT_HR 0x5 +#define AM_HAL_RTC_ALM_RPT_MIN 0x6 +#define AM_HAL_RTC_ALM_RPT_SEC 0x7 +#define AM_HAL_RTC_ALM_RPT_10TH 0x8 +#define AM_HAL_RTC_ALM_RPT_100TH 0x9 +//! @} + +//***************************************************************************** +// +//! @name RTC Alarm 100 Interval. +//! @brief Macro definitions for the RTC alarm ms intervals. +//! +//! These macros are used inside the #am_hal_rtc_alarm_interval_set function +//! when 10ms and 100ms repeated alarm intervals are desired. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_RTC_ALM100_DEFAULT 0x00 +#define AM_HAL_RTC_ALM100_10TH 0xF0 +#define AM_HAL_RTC_ALM100_100TH 0xFF +//! @} + +//***************************************************************************** +// +//! @brief The basic time structure used by the HAL for RTC interaction. +//! +//! All values are positive whole numbers. The HAL routines convert back and +//! forth to BCD. +// +//***************************************************************************** +typedef struct am_hal_rtc_time_struct +{ + uint32_t ui32ReadError; + uint32_t ui32CenturyEnable; + uint32_t ui32Weekday; + uint32_t ui32Century; + uint32_t ui32Year; + uint32_t ui32Month; + uint32_t ui32DayOfMonth; + uint32_t ui32Hour; + uint32_t ui32Minute; + uint32_t ui32Second; + uint32_t ui32Hundredths; +}am_hal_rtc_time_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_rtc_osc_select(uint32_t ui32OSC); +extern void am_hal_rtc_osc_enable(void); +extern void am_hal_rtc_osc_disable(void); +extern void am_hal_rtc_time_12hour(bool b12Hour); +extern void am_hal_rtc_time_set(am_hal_rtc_time_t *pTime); +extern uint32_t am_hal_rtc_time_get(am_hal_rtc_time_t *pTime); +extern void am_hal_rtc_alarm_interval_set(uint32_t ui32RepeatInterval); +extern void am_hal_rtc_alarm_set(am_hal_rtc_time_t *pTime, + uint32_t ui32RepeatInterval); +extern void am_hal_rtc_alarm_get(am_hal_rtc_time_t *pTime); +extern void am_hal_rtc_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_rtc_int_enable_get(void); +extern void am_hal_rtc_int_disable(uint32_t ui32Interrupt); +extern void am_hal_rtc_int_clear(uint32_t ui32Interrupt); +extern void am_hal_rtc_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_rtc_int_status_get(bool bEnabledOnly); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_RTC_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.c b/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.c new file mode 100644 index 0000000000..0cdd706c9e --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.c @@ -0,0 +1,525 @@ +//***************************************************************************** +// +// am_hal_stimer.c +//! @file +//! +//! @brief Functions for interfacing with the system timer (STIMER). +//! +//! @addtogroup stimer2 System Timer (STIMER) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Set up the stimer. +//! +//! @param ui32STimerConfig is the value to load into the configuration reg. +//! +//! This function should be used to perform the initial set-up of the +//! stimer. +//! +//! @return The 32-bit current config of the STimer Config register +// +//***************************************************************************** +uint32_t +am_hal_stimer_config(uint32_t ui32STimerConfig) +{ + uint32_t ui32CurrVal; + + // + // Read the current config + // + ui32CurrVal = AM_REG(CTIMER, STCFG); + + // + // Write our configuration value. + // + AM_REG(CTIMER, STCFG) = ui32STimerConfig; + + // + // If all of the clock sources are not HFRC, disable LDO when sleeping if timers are enabled. + // + if ( (AM_BFR(CTIMER, STCFG, CLKSEL) == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) || + (AM_BFR(CTIMER, STCFG, CLKSEL) == AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) ) + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 0); + } + else + { + AM_BFW(PWRCTRL, MISCOPT, DIS_LDOLPMODE_TIMERS, 1); + } + return ui32CurrVal; +} + +//***************************************************************************** +// +//! @brief Get the current stimer value. +//! +//! This function can be used to read, uninvasively, the value in the stimer. +//! +//! @return The 32-bit value from the STimer counter register. +// +//***************************************************************************** +uint32_t +am_hal_stimer_counter_get(void) +{ + return AM_REG(CTIMER, STTMR); +} + +//***************************************************************************** +// +//! @brief Clear the stimer counter. +//! +//! This function clears the STimer Counter and leaves the stimer running. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_counter_clear(void) +{ + // + // Set the clear bit + // + AM_REG(CTIMER, STCFG) |= AM_REG_CTIMER_STCFG_CLEAR_M; + + // + // Reset the clear bit + // + AM_REG(CTIMER, STCFG) &= ~AM_REG_CTIMER_STCFG_CLEAR_M; +} + +//***************************************************************************** +// +//! @brief Set the compare value. +//! +//! @param ui32CmprInstance is the compare register instance number (0-7). +//! @param ui32Delta is the value to add to the STimer counter and load into +//! the comparator register. +//! +//! NOTE: There is no way to set an absolute value into a comparator register. +//! Only deltas added to the STimer counter can be written to the compare +//! registers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance, uint32_t ui32Delta) +{ + if ( ui32CmprInstance > 7 ) + { + return; + } + + AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)) = ui32Delta; +} + +//***************************************************************************** +// +//! @brief Get the current stimer compare register value. +//! +//! @param ui32CmprInstance is the compare register instance number (0-7). +//! +//! This function can be used to read the value in an stimer compare register. +//! +//! +//! @return None. +// +//***************************************************************************** +uint32_t +am_hal_stimer_compare_get(uint32_t ui32CmprInstance) +{ + if ( ui32CmprInstance > 7 ) + { + return 0; + } + + return AM_REGVAL(AM_REG_STIMER_COMPARE(0, ui32CmprInstance)); +} + +//***************************************************************************** +// +//! @brief Start capturing data with the specified capture register. +//! +//! @param ui32CaptureNum is the Capture Register Number to read (0-3). +//! ui32GPIONumber is the pin number. +//! bPolarity: false (0) = Capture on low to high transition. +//! true (1) = Capture on high to low transition. +//! +//! Use this function to start capturing. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_capture_start(uint32_t ui32CaptureNum, + uint32_t ui32GPIONumber, + bool bPolarity) +{ + uint32_t ui32CapCtrl; + + if ( ui32GPIONumber > (AM_HAL_GPIO_MAX_PADS-1) ) + { + return; + } + + // + // Set the polarity and pin selection in the GPIO block. + // + switch (ui32CaptureNum) + { + case 0: + AM_BFW(GPIO, STMRCAP, STPOL0, bPolarity); + AM_BFW(GPIO, STMRCAP, STSEL0, ui32GPIONumber); + ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_M; + break; + case 1: + AM_BFW(GPIO, STMRCAP, STPOL1, bPolarity); + AM_BFW(GPIO, STMRCAP, STSEL1, ui32GPIONumber); + ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_B_M; + break; + case 2: + AM_BFW(GPIO, STMRCAP, STPOL2, bPolarity); + AM_BFW(GPIO, STMRCAP, STSEL2, ui32GPIONumber); + ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_C_M; + break; + case 3: + AM_BFW(GPIO, STMRCAP, STPOL3, bPolarity); + AM_BFW(GPIO, STMRCAP, STSEL3, ui32GPIONumber); + ui32CapCtrl = AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_D_M; + break; + default: + return; // error concealment. + } + + // + // Enable it in the CTIMER Block + // + AM_REG(CTIMER, CAPTURE_CONTROL) |= ui32CapCtrl; +} + +//***************************************************************************** +// +//! @brief Start capturing data with the specified capture register. +//! +//! @param ui32CaptureNum is the Capture Register Number to read. +//! +//! Use this function to start capturing. +//! +//! @return None. +// +//***************************************************************************** +void am_hal_stimer_capture_stop(uint32_t ui32CaptureNum) +{ + // + // Disable it in the CTIMER block. + // + AM_REG(CTIMER, CAPTURE_CONTROL) &= + ~(AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_M << + ((AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_B_S - + AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_S) * ui32CaptureNum)); +} + +//***************************************************************************** +// +//! @brief Get the current stimer capture register value. +//! +//! @param ui32CaptureNum is the Capture Register Number to read. +//! +//! This function can be used to read the value in an stimer capture register. +//! +//! +//! @return None. +// +//***************************************************************************** +uint32_t am_hal_stimer_capture_get(uint32_t ui32CaptureNum) +{ + if ( ui32CaptureNum > 7 ) + { + return 0; + } + + return AM_REGVAL(AM_REG_STIMER_CAPTURE(0, ui32CaptureNum)); +} + +//***************************************************************************** +// +//! @brief Enables the selected system timer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will enable the selected interrupts in the STIMER interrupt +//! enable register. In order to receive an interrupt from an stimer component, +//! you will need to enable the interrupt for that component in this main +//! register, as well as in the stimer configuration register (accessible though +//! am_hal_stimer_config()), and in the NVIC. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_STIMER_INT_COMPAREA +//! AM_HAL_STIMER_INT_COMPAREB +//! AM_HAL_STIMER_INT_COMPAREC +//! AM_HAL_STIMER_INT_COMPARED +//! AM_HAL_STIMER_INT_COMPAREE +//! AM_HAL_STIMER_INT_COMPAREF +//! AM_HAL_STIMER_INT_COMPAREG +//! AM_HAL_STIMER_INT_COMPAREH +//! +//! AM_HAL_STIMER_INT_OVERFLOW +//! +//! AM_HAL_STIMER_INT_CAPTUREA +//! AM_HAL_STIMER_INT_CAPTUREB +//! AM_HAL_STIMER_INT_CAPTUREC +//! AM_HAL_STIMER_INT_CAPTURED +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_int_enable(uint32_t ui32Interrupt) +{ + // + // Enable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, STMINTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return the enabled stimer interrupts. +//! +//! This function will return all enabled interrupts in the STIMER +//! interrupt enable register. +//! +//! @return return enabled interrupts. This will be a logical or of: +//! +//! AM_HAL_STIMER_INT_COMPAREA +//! AM_HAL_STIMER_INT_COMPAREB +//! AM_HAL_STIMER_INT_COMPAREC +//! AM_HAL_STIMER_INT_COMPARED +//! AM_HAL_STIMER_INT_COMPAREE +//! AM_HAL_STIMER_INT_COMPAREF +//! AM_HAL_STIMER_INT_COMPAREG +//! AM_HAL_STIMER_INT_COMPAREH +//! +//! AM_HAL_STIMER_INT_OVERFLOW +//! +//! AM_HAL_STIMER_INT_CAPTUREA +//! AM_HAL_STIMER_INT_CAPTUREB +//! AM_HAL_STIMER_INT_CAPTUREC +//! AM_HAL_STIMER_INT_CAPTURED +//! +//! @return Return the enabled timer interrupts. +// +//***************************************************************************** +uint32_t +am_hal_stimer_int_enable_get(void) +{ + // + // Return enabled interrupts. + // + return AM_REGn(CTIMER, 0, STMINTEN); +} + +//***************************************************************************** +// +//! @brief Disables the selected stimer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will disable the selected interrupts in the STIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_STIMER_INT_COMPAREA +//! AM_HAL_STIMER_INT_COMPAREB +//! AM_HAL_STIMER_INT_COMPAREC +//! AM_HAL_STIMER_INT_COMPARED +//! AM_HAL_STIMER_INT_COMPAREE +//! AM_HAL_STIMER_INT_COMPAREF +//! AM_HAL_STIMER_INT_COMPAREG +//! AM_HAL_STIMER_INT_COMPAREH +//! +//! AM_HAL_STIMER_INT_OVERFLOW +//! +//! AM_HAL_STIMER_INT_CAPTUREA +//! AM_HAL_STIMER_INT_CAPTUREB +//! AM_HAL_STIMER_INT_CAPTUREC +//! AM_HAL_STIMER_INT_CAPTURED +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_int_disable(uint32_t ui32Interrupt) +{ + // + // Disable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, STMINTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Sets the selected stimer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will set the selected interrupts in the STIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_STIMER_INT_COMPAREA +//! AM_HAL_STIMER_INT_COMPAREB +//! AM_HAL_STIMER_INT_COMPAREC +//! AM_HAL_STIMER_INT_COMPARED +//! AM_HAL_STIMER_INT_COMPAREE +//! AM_HAL_STIMER_INT_COMPAREF +//! AM_HAL_STIMER_INT_COMPAREG +//! AM_HAL_STIMER_INT_COMPAREH +//! +//! AM_HAL_STIMER_INT_OVERFLOW +//! +//! AM_HAL_STIMER_INT_CAPTUREA +//! AM_HAL_STIMER_INT_CAPTUREB +//! AM_HAL_STIMER_INT_CAPTUREC +//! AM_HAL_STIMER_INT_CAPTURED +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_int_set(uint32_t ui32Interrupt) +{ + // + // Set the interrupts. + // + AM_REGn(CTIMER, 0, STMINTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Clears the selected stimer interrupt. +//! +//! @param ui32Interrupt is the interrupt to be used. +//! +//! This function will clear the selected interrupts in the STIMER +//! interrupt register. +//! +//! ui32Interrupt should be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_STIMER_INT_COMPAREA +//! AM_HAL_STIMER_INT_COMPAREB +//! AM_HAL_STIMER_INT_COMPAREC +//! AM_HAL_STIMER_INT_COMPARED +//! AM_HAL_STIMER_INT_COMPAREE +//! AM_HAL_STIMER_INT_COMPAREF +//! AM_HAL_STIMER_INT_COMPAREG +//! AM_HAL_STIMER_INT_COMPAREH +//! +//! AM_HAL_STIMER_INT_OVERFLOW +//! +//! AM_HAL_STIMER_INT_CAPTUREA +//! AM_HAL_STIMER_INT_CAPTUREB +//! AM_HAL_STIMER_INT_CAPTUREC +//! AM_HAL_STIMER_INT_CAPTURED +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_stimer_int_clear(uint32_t ui32Interrupt) +{ + // + // Disable the interrupt at the module level. + // + AM_REGn(CTIMER, 0, STMINTCLR) = ui32Interrupt; +} + + +//***************************************************************************** +// +//! @brief Returns either the enabled or raw stimer interrupt status. +//! +//! This function will return the stimer interrupt status. +//! +//! @bEnabledOnly if true returns the status of the enabled interrupts +//! only. +//! +//! The return value will be the logical OR of one or more of the following +//! values: +//! +//! +//! @return Returns the stimer interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_stimer_int_status_get(bool bEnabledOnly) +{ + // + // Return the desired status. + // + uint32_t ui32RetVal = AM_REGn(CTIMER, 0, STMINTSTAT); + + if ( bEnabledOnly ) + { + ui32RetVal &= AM_REGn(CTIMER, 0, STMINTEN); + } + + return ui32RetVal; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.h b/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.h new file mode 100644 index 0000000000..bd4b09feae --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_stimer.h @@ -0,0 +1,242 @@ +//***************************************************************************** +// +// am_hal_stimer.h +//! @file +//! +//! @brief Functions for accessing and configuring the STIMER. +//! +//! @addtogroup stimer2 Counter/Timer (STIMER) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_STIMER_H +#define AM_HAL_STIMER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// +// Compute address of a given COMPARE or CAPTURE register. +// Note - For Apollo2, the parameter n should be 0 (as only 1 stimer module +// exists) and the parameter r should be 0-7 (compare) or 0-3 (capture). +// +#define AM_REG_STIMER_COMPARE(n, r) (AM_REG_CTIMERn(n) + \ + AM_REG_CTIMER_SCMPR0_O + (r * 4)) + +#define AM_REG_STIMER_CAPTURE(n, r) (AM_REG_CTIMERn(n) + \ + AM_REG_CTIMER_SCAPT0_O + (r * 4)) + +//***************************************************************************** +// +//! @name Interrupt Status Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to set and clear interrupt bits +//! @{ +// +//***************************************************************************** +#define AM_HAL_STIMER_INT_COMPAREA AM_REG_CTIMER_STMINTSTAT_COMPAREA_M +#define AM_HAL_STIMER_INT_COMPAREB AM_REG_CTIMER_STMINTSTAT_COMPAREB_M +#define AM_HAL_STIMER_INT_COMPAREC AM_REG_CTIMER_STMINTSTAT_COMPAREC_M +#define AM_HAL_STIMER_INT_COMPARED AM_REG_CTIMER_STMINTSTAT_COMPARED_M +#define AM_HAL_STIMER_INT_COMPAREE AM_REG_CTIMER_STMINTSTAT_COMPAREE_M +#define AM_HAL_STIMER_INT_COMPAREF AM_REG_CTIMER_STMINTSTAT_COMPAREF_M +#define AM_HAL_STIMER_INT_COMPAREG AM_REG_CTIMER_STMINTSTAT_COMPAREG_M +#define AM_HAL_STIMER_INT_COMPAREH AM_REG_CTIMER_STMINTSTAT_COMPAREH_M + +#define AM_HAL_STIMER_INT_OVERFLOW AM_REG_CTIMER_STMINTSTAT_OVERFLOW_M + +#define AM_HAL_STIMER_INT_CAPTUREA AM_REG_CTIMER_STMINTSTAT_CAPTUREA_M +#define AM_HAL_STIMER_INT_CAPTUREB AM_REG_CTIMER_STMINTSTAT_CAPTUREB_M +#define AM_HAL_STIMER_INT_CAPTUREC AM_REG_CTIMER_STMINTSTAT_CAPTUREC_M +#define AM_HAL_STIMER_INT_CAPTURED AM_REG_CTIMER_STMINTSTAT_CAPTURED_M + +//! @} + + + +//***************************************************************************** +// +//! @name STimer Configuration Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to set and clear interrupt bits +//! @{ +// +//***************************************************************************** +#define AM_HAL_STIMER_CFG_THAW \ + AM_REG_CTIMER_STCFG_FREEZE_THAW +#define AM_HAL_STIMER_CFG_FREEZE \ + AM_REG_CTIMER_STCFG_FREEZE_FREEZE +#define AM_HAL_STIMER_CFG_RUN \ + AM_REG_CTIMER_STCFG_CLEAR_RUN +#define AM_HAL_STIMER_CFG_CLEAR \ + AM_REG_CTIMER_STCFG_CLEAR_CLEAR +#define AM_HAL_STIMER_CFG_COMPARE_A_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_A_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_B_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_B_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_C_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_C_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_D_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_D_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_E_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_E_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_F_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_F_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_G_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_G_EN_ENABLE +#define AM_HAL_STIMER_CFG_COMPARE_H_ENABLE \ + AM_REG_CTIMER_STCFG_COMPARE_H_EN_ENABLE + +//! @} + +//***************************************************************************** +// +//! @name Clock Configuration options +//! @brief STimer Configuration register options. +//! +//! These options are to be used with the am_hal_stimer_config() function. +//! @{ +// +//***************************************************************************** +#define AM_HAL_STIMER_NO_CLK \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_NOCLK) +#define AM_HAL_STIMER_HFRC_3MHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV16) +#define AM_HAL_STIMER_HFRC_187_5KHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_HFRC_DIV256) +#define AM_HAL_STIMER_XTAL_32KHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_XTAL_DIV1) +#define AM_HAL_STIMER_XTAL_16KHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_XTAL_DIV2) +#define AM_HAL_STIMER_XTAL_1KHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_XTAL_DIV32) +#define AM_HAL_STIMER_LFRC_1KHZ \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_LFRC_DIV1) +#define AM_HAL_STIMER_HFRC_CTIMER0A \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_CTIMER0A) +#define AM_HAL_STIMER_HFRC_CTIMER0B \ + AM_REG_CTIMER_STCFG_CLKSEL(AM_REG_CTIMER_STCFG_CLKSEL_CTIMER0B) +//! @} + + + +//***************************************************************************** +// +//! @name Capture Control Register options. +//! @brief Configuration options for capture control register. +//! +//! These options are to be used with the am_hal_stimer_capture_control_set +//! function. +//! @{ +// +//***************************************************************************** +#define AM_HAL_STIMER_CAPTURE_A_ENABLE \ + AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_A_ENABLE +#define AM_HAL_STIMER_CAPTURE_B_ENABLE \ + AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_B_ENABLE +#define AM_HAL_STIMER_CAPTURE_C_ENABLE \ + AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_C_ENABLE +#define AM_HAL_STIMER_CAPTURE_D_ENABLE \ + AM_REG_CTIMER_CAPTURE_CONTROL_CAPTURE_D_ENABLE + +//! @} + + +//***************************************************************************** +// +// +// +//***************************************************************************** + +//***************************************************************************** +// +// Stimer configuration structure +// +//***************************************************************************** +typedef struct +{ + // + //! Configuration options for the STIMER + // + uint32_t ui32STimerConfig; +} +am_hal_stimer_config_t; + + + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern uint32_t am_hal_stimer_config(uint32_t ui32STimerConfig); +extern uint32_t am_hal_stimer_counter_get(void); +extern void am_hal_stimer_counter_clear(void); +extern void am_hal_stimer_compare_delta_set(uint32_t ui32CmprInstance, + uint32_t ui32Delta); +extern uint32_t am_hal_stimer_compare_get(uint32_t ui32CmprInstance); +extern void am_hal_stimer_capture_start(uint32_t ui32CaptureNum, + uint32_t ui32GPIONumber, + bool bPolarity); +extern void am_hal_stimer_capture_stop(uint32_t ui32CaptureNum); +extern uint32_t am_hal_stimer_capture_get(uint32_t ui32CaptureNum); +extern void am_hal_stimer_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_stimer_int_enable_get(void); +extern void am_hal_stimer_int_disable(uint32_t ui32Interrupt); +extern void am_hal_stimer_int_set(uint32_t ui32Interrupt); +extern void am_hal_stimer_int_clear(uint32_t ui32Interrupt); +extern uint32_t am_hal_stimer_int_status_get(bool bEnabledOnly); + + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_STIMER_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c new file mode 100644 index 0000000000..50e0b67915 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.c @@ -0,0 +1,851 @@ +//***************************************************************************** +// +// am_hal_sysctrl.c +//! @file +//! +//! @brief Functions for interfacing with the M4F system control registers +//! +//! @addtogroup sysctrl2 System Control (SYSCTRL) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Local macro constants +// +//***************************************************************************** +// +// Define ZX workaround values. +// These values are defined by the factory. +// +#define COREZXVALUE 0x07 +#define MEMZXVALUE 0x07 + +// +// Define values for g_ui32CoreBuck, which indicates which timer carries +// the signal for the CORE Buck, and which also implies that the other timer +// carries the signal for the MEM buck. +// +#define COREBUCK_TIMERA 1 // Core buck signal comes in on timer A +#define COREBUCK_TIMERB 2 // Core buck signal comes in on timer B + +// +// Define the bit values for static function g_buckZX_chk; +// +#define CHKBUCKZX_BUCKS 0x01 // The bucks are enabled +#define CHKBUCKZX_REV 0x02 // This chip rev needs the workaround +#define CHKBUCKZX_TIMER 0x04 // A valid timer has been allocated +#define CHKBUCKZX_DEVEN 0x08 // Devices are powered up and enabled + +//***************************************************************************** +// +// Prototypes +// +//***************************************************************************** +static void am_hal_sysctrl_buckA_ctimer_isr(void); +static void am_hal_sysctrl_buckB_ctimer_isr(void); + +//***************************************************************************** +// +// Globals +// +//***************************************************************************** +static volatile uint32_t g_ui32BuckTimer = 0; +static volatile uint32_t g_ui32BuckInputs = 0; +static volatile bool g_bBuckRestoreComplete = false; +static volatile bool g_bBuckTimed = false; +static uint32_t g_ui32SaveCoreBuckZX, g_ui32SaveMemBuckZX; +static uint32_t g_buckZX_chk = 0; +static volatile uint32_t g_ui32CoreBuck; + +// +// Timer configuration for BUCK inputs. +// +static const am_hal_ctimer_config_t g_sBuckTimer = +{ + // Don't link timers. + 0, + + // Set up Timer0A. + (AM_HAL_CTIMER_FN_ONCE | + AM_HAL_CTIMER_INT_ENABLE | + AM_HAL_CTIMER_BUCK), + + // Set up Timer0B. + (AM_HAL_CTIMER_FN_ONCE | + AM_HAL_CTIMER_INT_ENABLE | + AM_HAL_CTIMER_BUCK), +}; + +//***************************************************************************** +// +// Determine if we need to do the zero cross workaround on this device. +// Three criteria are used. All three must be true. +// 1. Are the bucks enabled? +// 2. Is the chip rev appropriate for the workaround? +// 3. Has a timer been allocated to do the workaround? +// 4. Are certain peripherals powered up? +// +// Saves the bitmask to the global g_buckZX_chk. +// Bitmask bits are defined as: CHKBUCKZX_BUCKS, CHKBUCKZX_REV, CHKBUCKZX_TIMER. +// +// Returns true if all criteria are met, false otherwise. +// g_buckZX_chk can be probed to determine which criteria passed or failed. +// +//***************************************************************************** +static bool +buckZX_chk(void) +{ + uint32_t ui32SupplySrc; + + // + // Is this chip rev appropriate to do the workaround? + // + g_buckZX_chk = AM_BFM(MCUCTRL, CHIPREV, REVMAJ) == AM_REG_MCUCTRL_CHIPREV_REVMAJ_B ? + CHKBUCKZX_REV : 0x0; + + // + // Has a timer been configured to handle the workaround? + // + g_buckZX_chk |= ( g_ui32BuckTimer - 1 ) <= BUCK_TIMER_MAX ? + CHKBUCKZX_TIMER : 0x0; + + // + // Are either or both of the bucks actually enabled? + // + ui32SupplySrc = AM_REG(PWRCTRL, SUPPLYSRC); + + g_buckZX_chk |= (ui32SupplySrc & + (AM_REG_PWRCTRL_SUPPLYSRC_COREBUCKEN_M | + AM_REG_PWRCTRL_SUPPLYSRC_MEMBUCKEN_M) ) ? + CHKBUCKZX_BUCKS : 0x0; + + // + // Finally, if any peripheral is already powered up, we don't need to do the + // ZX workaround because in this case the bucks remain in active mode. + // + ui32SupplySrc = AM_REG(PWRCTRL, DEVICEEN); + + g_buckZX_chk |= ( ui32SupplySrc & + (AM_REG_PWRCTRL_DEVICEEN_PDM_M | + AM_REG_PWRCTRL_DEVICEEN_UART1_M | + AM_REG_PWRCTRL_DEVICEEN_UART0_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER5_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER4_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER3_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER2_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER1_M | + AM_REG_PWRCTRL_DEVICEEN_IO_MASTER0_M | + AM_REG_PWRCTRL_DEVICEEN_IO_SLAVE_M) ) ? + 0x0 : CHKBUCKZX_DEVEN; + + // + // If all 4 criteria were met, we're good to do the workaround. + // + return ( g_buckZX_chk == + (CHKBUCKZX_BUCKS | CHKBUCKZX_REV | + CHKBUCKZX_TIMER | CHKBUCKZX_DEVEN) ) ? true : false; +} + +//***************************************************************************** +// +// Set the buck zero cross settings to the values given. +// +// ui32Flags, one or more of the following: +// SETBUCKZX_USE_PROVIDED_SETTINGS - Use the values provided in the parameters +// to set the trim value(s). +// SETBUCKZX_USE_SAVED_SETTINGS - Use the values that were previously saved +// to set the trim value(s). +// SETBUCKZX_SAVE_CURR_SETTINGS - Save the current trim values before +// setting the new ones. +// SETBUCKZX_RESTORE_CORE_ONLY - Restore the Core trim and save the current +// value of the core buck trim iff +// SETBUCKZX_SAVE_CURR_SETTINGS is set. +// SETBUCKZX_RESTORE_MEM_ONLY - Restore the Mem trim and save the current +// value of the mem buck trim iff +// SETBUCKZX_SAVE_CURR_SETTINGS is set. +// SETBUCKZX_RESTORE_BOTH - Restore both buck trims and save the +// current value of both iff +// SETBUCKZX_SAVE_CURR_SETTINGS is set. +// +//***************************************************************************** +#define SETBUCKZX_USE_PROVIDED_SETTINGS 0x01 +#define SETBUCKZX_USE_SAVED_SETTINGS 0x02 +#define SETBUCKZX_SAVE_CURR_SETTINGS 0x04 +#define SETBUCKZX_RESTORE_CORE_ONLY 0x10 +#define SETBUCKZX_RESTORE_MEM_ONLY 0x20 +#define SETBUCKZX_RESTORE_BOTH ( SETBUCKZX_RESTORE_CORE_ONLY | \ + SETBUCKZX_RESTORE_MEM_ONLY ) +static void +setBuckZX(uint32_t ui32CoreBuckZX, uint32_t ui32MemBuckZX, uint32_t ui32Flags) +{ + uint32_t ui32SaveCore, ui32SaveMem, ui32NewCore, ui32NewMem; + bool bDoRestore = false; + + // + // Begin critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Get the current zero cross trim values. + // + ui32SaveCore = AM_BFR(MCUCTRL, BUCK3, COREBUCKZXTRIM); + ui32SaveMem = AM_BFR(MCUCTRL, BUCK3, MEMBUCKZXTRIM); + + // + // Determine which values will be restored. + // + if ( ui32Flags & SETBUCKZX_USE_SAVED_SETTINGS ) + { + // + // Use saved settings + // + ui32NewCore = g_ui32SaveCoreBuckZX; + ui32NewMem = g_ui32SaveMemBuckZX; + bDoRestore = true; + } + else if ( ui32Flags & SETBUCKZX_USE_PROVIDED_SETTINGS ) + { + // + // Use settings provided in the call parameters + // + ui32NewCore = ui32CoreBuckZX; + ui32NewMem = ui32MemBuckZX; + bDoRestore = true; + } + + // + // Restore the buck Core and Mem trim registers. + // + if ( bDoRestore ) + { + if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY ) + { + AM_BFW(MCUCTRL, BUCK3, COREBUCKZXTRIM, ui32NewCore); + } + + if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY ) + { + AM_BFW(MCUCTRL, BUCK3, MEMBUCKZXTRIM, ui32NewMem); + } + } + + if ( ui32Flags & SETBUCKZX_SAVE_CURR_SETTINGS ) + { + // + // Save off the zero cross values as read on entry to the function. + // + if ( ui32Flags & SETBUCKZX_RESTORE_CORE_ONLY ) + { + g_ui32SaveCoreBuckZX = ui32SaveCore; + } + + if ( ui32Flags & SETBUCKZX_RESTORE_MEM_ONLY ) + { + g_ui32SaveMemBuckZX = ui32SaveMem; + } + } + + // + // Done with critical section. + // + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +//! @brief Place the core into sleep or deepsleep. +//! +//! @param bSleepDeep - False for Normal or True Deep sleep. +//! +//! This function puts the MCU to sleep or deepsleep depending on bSleepDeep. +//! +//! Valid values for bSleepDeep are: +//! +//! AM_HAL_SYSCTRL_SLEEP_NORMAL +//! AM_HAL_SYSCTRL_SLEEP_DEEP +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_sleep(bool bSleepDeep) +{ + uint32_t ui32Critical; +// uint32_t ui32DebugGpioSleep = g_ui32DebugGpioSleep - 1; + bool bBuckZX_chk; + volatile uint32_t ui32BuckTimer; + + // + // Disable interrupts and save the previous interrupt state. + // + ui32Critical = am_hal_interrupt_master_disable(); + + // + // If the user selected DEEPSLEEP and the TPIU is off, attempt to enter + // DEEP SLEEP. + // + if ((bSleepDeep == AM_HAL_SYSCTRL_SLEEP_DEEP) && + (AM_BFM(MCUCTRL, TPIUCTRL, ENABLE) == AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS)) + { + // + // Prepare the core for deepsleep (write 1 to the DEEPSLEEP bit). + // + AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 1); + + // + // Check if special buck handling is needed + // + bBuckZX_chk = buckZX_chk(); + + if ( bBuckZX_chk ) + { + ui32BuckTimer = g_ui32BuckTimer - 1; + + // + // Before going to sleep, clear the buck timers. + // This will also handle the case where we're going back to + // sleep before the buck sequence has even completed. + // + am_hal_ctimer_clear(ui32BuckTimer, AM_HAL_CTIMER_BOTH); + + // + // Set CMPR0 of both timerA and timerB to the period value + // + #define TIMER_PERIOD_BUCKS 1 + am_hal_ctimer_period_set(ui32BuckTimer, + AM_HAL_CTIMER_BOTH, + TIMER_PERIOD_BUCKS | + (TIMER_PERIOD_BUCKS << 16), + 0); + + // + // Disable bucks before going to sleep. + // + am_hal_pwrctrl_bucks_disable(); + } + + // + // Execute the sleep instruction. + // + AM_ASM_WFI; + + // + // Return from sleep + // + if ( bBuckZX_chk ) + { + // + // Adjust the core and mem trims + // + setBuckZX(COREZXVALUE, MEMZXVALUE, + SETBUCKZX_USE_PROVIDED_SETTINGS | + SETBUCKZX_RESTORE_BOTH ); + + // + // Delay for 2us before enabling bucks. + // + am_hal_flash_delay( FLASH_CYCLES_US(2) ); + + // + // Turn on the bucks + // + am_hal_pwrctrl_bucks_enable(); + + // + // Get the actual timer number + // + ui32BuckTimer = g_ui32BuckTimer - 1; + + // + // Initialize the complete flag + // + g_bBuckRestoreComplete = false; + + // + // Initialize the input flags + // + g_ui32BuckInputs = 0; + + // + // Delay for 5us to make sure we're receiving clean buck signals. + // + am_hal_flash_delay( FLASH_CYCLES_US(5) ); + + // + // Start timers (set the enable bit, clear the clear bit) + // + am_hal_ctimer_start(ui32BuckTimer, AM_HAL_CTIMER_BOTH); + } + else + { + // + // Since we're not doing anything, we're done, so set the done flag. + // + g_bBuckRestoreComplete = true; + } + } + else + { + // + // Prepare the core for normal sleep (write 0 to the DEEPSLEEP bit). + // + AM_BFW(SYSCTRL, SCR, SLEEPDEEP, 0); + + // + // Go to sleep. + // + AM_ASM_WFI; + } + + // + // Restore the interrupt state. + // + am_hal_interrupt_master_set(ui32Critical); +} + +//***************************************************************************** +// +//! @brief Enable the floating point module. +//! +//! Call this function to enable the ARM hardware floating point module. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_fpu_enable(void) +{ + // + // Enable access to the FPU in both privileged and user modes. + // NOTE: Write 0s to all reserved fields in this register. + // + AM_REG(SYSCTRL, CPACR) = (AM_REG_SYSCTRL_CPACR_CP11(0x3) | + AM_REG_SYSCTRL_CPACR_CP10(0x3)); +} + +//***************************************************************************** +// +//! @brief Disable the floating point module. +//! +//! Call this function to disable the ARM hardware floating point module. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_fpu_disable(void) +{ + // + // Disable access to the FPU in both privileged and user modes. + // NOTE: Write 0s to all reserved fields in this register. + // + AM_REG(SYSCTRL, CPACR) = 0x00000000 & + ~(AM_REG_SYSCTRL_CPACR_CP11(0x3) | + AM_REG_SYSCTRL_CPACR_CP10(0x3)); +} + +//***************************************************************************** +// +//! @brief Enable stacking of FPU registers on exception entry. +//! +//! @param bLazy - Set to "true" to enable "lazy stacking". +//! +//! This function allows the core to save floating-point information to the +//! stack on exception entry. Setting the bLazy option enables "lazy stacking" +//! for interrupt handlers. Normally, mixing floating-point code and interrupt +//! driven routines causes increased interrupt latency, because the core must +//! save extra information to the stack upon exception entry. With the lazy +//! stacking option enabled, the core will skip the saving of floating-point +//! registers when possible, reducing average interrupt latency. +//! +//! @note This function should be called before the floating-point module is +//! used in interrupt-driven code. If it is not called, the core will not have +//! any way to save context information for floating-point variables on +//! exception entry. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_fpu_stacking_enable(bool bLazy) +{ + if ( bLazy ) + { + // + // Enable automatic saving of FPU registers on exception entry, using lazy + // context saving. + // + AM_REG(SYSCTRL, FPCCR) |= (AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) | + AM_REG_SYSCTRL_FPCCR_LSPEN(0x1)); + } + else + { + // + // Enable automatic saving of FPU registers on exception entry. + // + AM_REG(SYSCTRL, FPCCR) |= AM_REG_SYSCTRL_FPCCR_ASPEN(0x1); + } +} + +//***************************************************************************** +// +//! @brief Disable FPU register stacking on exception entry. +//! +//! This function disables all stacking of floating point registers for +//! interrupt handlers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_fpu_stacking_disable(void) +{ + // + // Enable automatic saving of FPU registers on exception entry, using lazy + // context saving. + // + AM_REG(SYSCTRL, FPCCR) &= ~(AM_REG_SYSCTRL_FPCCR_ASPEN(0x1) | + AM_REG_SYSCTRL_FPCCR_LSPEN(0x1)); +} + +//***************************************************************************** +// +//! @brief Issue a system wide reset using the AIRCR bit in the M4 system ctrl. +//! +//! This function issues a system wide reset (Apollo POR level reset). +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_sysctrl_aircr_reset(void) +{ + // + // Set the system reset bit in the AIRCR register + // + AM_REG(SYSCTRL, AIRCR) = AM_REG_SYSCTRL_AIRCR_VECTKEY(0x5FA) | + AM_REG_SYSCTRL_AIRCR_SYSRESETREQ(1); +} + +//***************************************************************************** +// +//! @brief Buck CTimer ISR initializer. +//! +//! @param ui32BuckTimerNumber - Timer number to be used for handling the buck. +//! Must be 0-3. +//! +//! If called with an invalid timer (that is, not 0 - 3, or greater than +//! BUCK_TIMER_MAX), then the workaround will not be enabled. +//! +//! Instead, the bucks will be initialized with a value that will avoid the +//! issues described in the Errata (ERR019). However, this will cause a +//! less efficient energy usage condtion. +//! +//! @return 0. +// +//***************************************************************************** +uint32_t +am_hal_sysctrl_buck_ctimer_isr_init(uint32_t ui32BuckTimerNumber) +{ + uint32_t ui32RetVal = 0; + + // + // Initialize the input flags + // + g_ui32BuckInputs = 0; + + // + // Initialize operation complete flag + // + g_bBuckRestoreComplete = false; + + // + // Initialize to assume there is no valid timer. + // + g_ui32BuckTimer = 0; + + if ( ui32BuckTimerNumber > BUCK_TIMER_MAX ) + { + if ( ( ui32BuckTimerNumber & 0xFFFF0000 ) == + AM_HAL_SYSCTRL_BUCK_CTIMER_ZX_CONSTANT ) + { + // + // The caller is asking for the hard option, which changes the + // settings to the more noise-immune, if less efficient, settings. + // While we're at it, go ahead and save off the current settings. + // + if ( (ui32BuckTimerNumber & 0x0000FFFF) == 0 ) + { + setBuckZX(COREZXVALUE, MEMZXVALUE, + SETBUCKZX_USE_PROVIDED_SETTINGS | + SETBUCKZX_SAVE_CURR_SETTINGS | + SETBUCKZX_RESTORE_BOTH ); + } + else + { + uint32_t ui32Core, ui32Mem; + + // + // Use the setting provided in the parameter. + // + ui32Core = (((ui32BuckTimerNumber & 0x001F) >> 0) - 1) & 0xF; + ui32Mem = (((ui32BuckTimerNumber & 0x1F00) >> 8) - 1) & 0xF; + + setBuckZX(ui32Core, ui32Mem, + SETBUCKZX_USE_PROVIDED_SETTINGS | + SETBUCKZX_SAVE_CURR_SETTINGS | + SETBUCKZX_RESTORE_BOTH ); + } + } + } + else + { + // + // Save off the current trim settings (but don't change any settings). + // + setBuckZX(0, 0, SETBUCKZX_SAVE_CURR_SETTINGS | SETBUCKZX_RESTORE_BOTH); + + // + // The timer number will be maintained as (n + 1). Therefore, a value + // of 0 saved in the global is an invalid timer. 1=timer0, 2=timer1... + // + g_ui32BuckTimer = ui32BuckTimerNumber + 1; + + // + // Register the timer ISRs + // + am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERA0C0 << + (ui32BuckTimerNumber * 2), + am_hal_sysctrl_buckA_ctimer_isr ); + + am_hal_ctimer_int_register( AM_HAL_CTIMER_INT_TIMERB0C0 << + (ui32BuckTimerNumber * 2), + am_hal_sysctrl_buckB_ctimer_isr ); + + // + // Determine which timer input (A or B) is core buck and which is mem + // buck based on the timer number. + // For CTIMER 0 & 1: Timer A is mem buck, Timer B is core buck + // For CTIMER 2 & 3: Timer A is core buck, Timer B is mem buck + // + if ( (ui32BuckTimerNumber == 0) || (ui32BuckTimerNumber == 1) ) + { + // + // Indicate that TimerB is core buck. + // + g_ui32CoreBuck = COREBUCK_TIMERB; + } + else + { + // + // Indicate that TimerA is core buck + // + g_ui32CoreBuck = COREBUCK_TIMERA; + } + + // + // Clear and configure the timers + // + am_hal_ctimer_clear(ui32BuckTimerNumber, AM_HAL_CTIMER_BOTH); + + am_hal_ctimer_config(ui32BuckTimerNumber, + (am_hal_ctimer_config_t*)&g_sBuckTimer); + + // + // Enable the interrupts for timers A and B + // + am_hal_ctimer_int_enable( (AM_HAL_CTIMER_INT_TIMERA0C0 | + AM_HAL_CTIMER_INT_TIMERB0C0 ) << + (ui32BuckTimerNumber * 2) ); + + // + // Enable the timer interrupt in the NVIC. + // + am_hal_interrupt_enable(AM_HAL_INTERRUPT_CTIMER); + } + + return ui32RetVal; +} + +//***************************************************************************** +// +// Get buck update complete status. +// +//***************************************************************************** +bool +am_hal_sysctrl_buck_update_complete(void) +{ + return g_bBuckRestoreComplete; +} + +//***************************************************************************** +// +// Buck CTIMER ISR (for handling buck switching via TimerA). +// +// Note: This handler assumes that the interrupt is cleared in am_ctimer_isr(). +// +//***************************************************************************** +static void +am_hal_sysctrl_buckA_ctimer_isr(void) +{ + volatile uint32_t ui32BuckTimer = g_ui32BuckTimer - 1; + + // + // Begin critical section. + // Although a relatively long time, the following 2us delay is critically + // timed for re-trimming the buck and thus cannot be extended. Therefore, + // we must keep it inside the critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Delay for 2us. + // + am_hal_flash_delay( FLASH_CYCLES_US(2) ); + + // + // Determine which buck (core or mem) needs to be updated. + // + if ( g_ui32CoreBuck == COREBUCK_TIMERA ) + { + // + // Timer A buck signal is the CORE buck. + // Restore the core buck. + // + setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY | + SETBUCKZX_USE_SAVED_SETTINGS ); + } + else + { + // + // Timer A buck signal is the MEM buck. + // Restore the mem buck. + // + setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY | + SETBUCKZX_USE_SAVED_SETTINGS ); + } + + g_ui32BuckInputs |= 0x1; + + if ( g_ui32BuckInputs == 0x3 ) + { + g_bBuckRestoreComplete = true; + g_ui32BuckInputs = 0; + } + + // + // End critical section. + // + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +// Buck CTIMER ISR (for handling buck switching via TimerB). +// +// Note: This handler assumes that the interrupt is cleared in am_ctimer_isr(). +// +//***************************************************************************** +static void +am_hal_sysctrl_buckB_ctimer_isr(void) +{ + volatile uint32_t ui32BuckTimer = g_ui32BuckTimer - 1; + + // + // Begin critical section. + // Although a relatively long time, the following 2us delay is critically + // timed for re-trimming the buck and thus cannot be extended. Therefore, + // we must keep it inside the critical section. + // + AM_CRITICAL_BEGIN_ASM + + // + // Delay for 2us. + // + am_hal_flash_delay( FLASH_CYCLES_US(2) ); + + // + // Determine which buck (core or mem) needs to be updated. + // + if ( g_ui32CoreBuck == COREBUCK_TIMERB ) + { + // + // Timer B buck signal is the CORE buck. + // Restore the core buck. + // + setBuckZX(0, 0, SETBUCKZX_RESTORE_CORE_ONLY | + SETBUCKZX_USE_SAVED_SETTINGS ); + } + else + { + // + // Timer B buck signal is the MEM buck. + // Restore the mem buck. + // + setBuckZX(0, 0, SETBUCKZX_RESTORE_MEM_ONLY | + SETBUCKZX_USE_SAVED_SETTINGS ); + } + + g_ui32BuckInputs |= 0x2; + + if ( g_ui32BuckInputs == 0x3 ) + { + g_bBuckRestoreComplete = true; + g_ui32BuckInputs = 0; + } + + // + // End critical section. + // + AM_CRITICAL_END_ASM +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.h b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.h new file mode 100644 index 0000000000..34c72b4173 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_sysctrl.h @@ -0,0 +1,119 @@ +//***************************************************************************** +// +//! am_hal_sysctrl.h +//! @file +//! +//! @brief Functions for interfacing with the M4F system control registers +//! +//! @addtogroup sysctrl2 System Control (SYSCTRL) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_SYSCTRL_H +#define AM_HAL_SYSCTRL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Definitions for sleep mode parameter +// +//***************************************************************************** +#define AM_HAL_SYSCTRL_SLEEP_DEEP true +#define AM_HAL_SYSCTRL_SLEEP_NORMAL false + +//***************************************************************************** +// +// Parameters for am_hal_sysctrl_buck_ctimer_isr_init() +// +//***************************************************************************** +// +// Define the maximum valid timer number +// +#define BUCK_TIMER_MAX (AM_HAL_CTIMER_TIMERS_NUM - 1) + +// +// Define the valid timer numbers +// +#define AM_HAL_SYSCTRL_BUCK_CTIMER_TIMER0 0 +#define AM_HAL_SYSCTRL_BUCK_CTIMER_TIMER1 1 +#define AM_HAL_SYSCTRL_BUCK_CTIMER_TIMER2 2 +#define AM_HAL_SYSCTRL_BUCK_CTIMER_TIMER3 3 + +// +// The following is an invalid timer number. If used, it is the caller telling +// the HAL to use the "Hard Option", which applies a constant value to the zero +// cross. The applied value is more noise immune, if less energy efficent. +// +#define AM_HAL_SYSCTRL_BUCK_CTIMER_ZX_CONSTANT 0x01000000 // No timer, apply a constant value + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_sysctrl_sleep(bool bSleepDeep); +extern void am_hal_sysctrl_fpu_enable(void); +extern void am_hal_sysctrl_fpu_disable(void); +extern void am_hal_sysctrl_fpu_stacking_enable(bool bLazy); +extern void am_hal_sysctrl_fpu_stacking_disable(void); +extern void am_hal_sysctrl_aircr_reset(void); + +// +// Apollo2 zero-cross buck/ctimer related functions +// +extern uint32_t am_hal_sysctrl_buck_ctimer_isr_init(uint32_t ui32BuckTimerNumber); +extern bool am_hal_sysctrl_buck_update_complete(void); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_SYSCTRL_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** + diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_systick.c b/bsp/apollo2/libraries/drivers/hal/am_hal_systick.c new file mode 100644 index 0000000000..3654910495 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_systick.c @@ -0,0 +1,453 @@ +//***************************************************************************** +// +// am_hal_systick.c +//! @file +//! +//! @brief Functions for interfacing with the SYSTICK +//! +//! @addtogroup systick2 System Timer (SYSTICK) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + + +//***************************************************************************** +// +// Macro definitions +// +//***************************************************************************** +#define SYSTICK_MAX_TICKS ((1 << 24)-1) +#define MAX_U32 (0xffffffff) + +//***************************************************************************** +// +//! @brief Start the SYSTICK. +//! +//! This function starts the systick timer. +//! +//! @note This timer does not run in deep-sleep mode as it runs from the core +//! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use +//! one of the ctimers instead. Also to note is this timer will consume higher +//! power than the ctimers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_start(void) +{ + // + // Start the systick timer. + // + AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_ENABLE_M; +} + +//***************************************************************************** +// +//! @brief Stop the SYSTICK. +//! +//! This function stops the systick timer. +//! +//! @note This timer does not run in deep-sleep mode as it runs from the core +//! clock, which is gated in deep-sleep. If a timer is needed in deep-sleep use +//! one of the ctimers instead. Also to note is this timer will consume higher +//! power than the ctimers. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_stop(void) +{ + // + // Stop the systick timer. + // + AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_ENABLE_M; +} + +//***************************************************************************** +// +//! @brief Enable the interrupt in the SYSTICK. +//! +//! This function enables the interupt in the systick timer. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_int_enable(void) +{ + // + // Enable the systick timer interrupt. + // + AM_REG(SYSTICK, SYSTCSR) |= AM_REG_SYSTICK_SYSTCSR_TICKINT_M; +} + +//***************************************************************************** +// +//! @brief Disable the interrupt in the SYSTICK. +//! +//! This function disables the interupt in the systick timer. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_int_disable(void) +{ + // + // Disable the systick timer interrupt. + // + AM_REG(SYSTICK, SYSTCSR) &= ~AM_REG_SYSTICK_SYSTCSR_TICKINT_M; +} + +//***************************************************************************** +// +//! @brief Reads the interrupt status. +//! +//! This function reads the interrupt status in the systick timer. +//! +//! @return the interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_systick_int_status_get(void) +{ + // + // Return the systick timer interrupt status. + // + return AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M; +} + +//***************************************************************************** +// +//! @brief Reset the interrupt in the SYSTICK. +//! +//! This function resets the systick timer by clearing out the configuration +//! register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_reset(void) +{ + // + // Reset the systick timer interrupt. + // + AM_REG(SYSTICK, SYSTCSR) = 0x0; +} + +//***************************************************************************** +// +//! @brief Load the value into the SYSTICK. +//! +//! @param ui32LoadVal the desired load value for the systick. Maximum value is +//! 0x00FF.FFFF. +//! +//! This function loads the desired value into the systick timer. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_systick_load(uint32_t ui32LoadVal) +{ + // + // Write the reload register. + // + AM_REG(SYSTICK, SYSTRVR) = ui32LoadVal; +} + +//***************************************************************************** +// +//! @brief Get the current count value in the SYSTICK. +//! +//! This function gets the current count value in the systick timer. +//! +//! @return Current count value. +// +//***************************************************************************** +uint32_t +am_hal_systick_count(void) +{ + // + // Return the current systick timer count value. + // + return AM_REG(SYSTICK, SYSTCVR); +} + +//***************************************************************************** +// +//! @brief Wait the specified number of ticks. +//! +//! This function delays for the given number of SysTick ticks. +//! +//! @note If the SysTick timer is being used elsewhere, it will be corrupted +//! by calling this function. +//! +//! @return 0 if successful. +// +//***************************************************************************** +uint32_t +am_hal_systick_wait_ticks(uint32_t u32Ticks) +{ + + if ( u32Ticks == 0 ) + { + u32Ticks++; // Make sure we get the COUNTFLAG + } + + // + // The proper SysTick initialization sequence is: (p 4-36 of the M4 UG). + // 1. Program reload value + // 2. Clear current value + // 3. Program CSR + // + // Set the reload value to the required number of ticks. + // + AM_REG(SYSTICK, SYSTRVR) = u32Ticks; + + // + // Clear the current count. + // + AM_REG(SYSTICK, SYSTCVR) = 0x0; + + // + // Set to use the processor clock, but don't cause an exception (we'll poll). + // + AM_REG(SYSTICK, SYSTCSR) = AM_REG_SYSTICK_SYSTCSR_ENABLE_M; + + // + // Poll till done + // + while ( !(AM_REG(SYSTICK, SYSTCSR) & AM_REG_SYSTICK_SYSTCSR_COUNTFLAG_M) ); + + // + // And disable systick before exiting. + // + AM_REG(SYSTICK, SYSTCSR) = 0; + + return 0; +} + +//***************************************************************************** +// +//! @brief Delay the specified number of microseconds. +//! +//! This function will use the SysTick timer to delay until the specified +//! number of microseconds have elapsed. It uses the processor clocks and +//! takes into account the current CORESEL setting. +//! +//! @note If the SysTick timer is being used elsewhere, it will be corrupted +//! by calling this function. +//! +//! @return Total number of SysTick ticks delayed. +// +//***************************************************************************** +uint32_t +am_hal_systick_delay_us(uint32_t u32NumUs) +{ + uint32_t u32ClkFreq, u32nLoops, u32Ticks, uRet; + uint32_t u32CoreSel = AM_BFR(CLKGEN, CCTRL, CORESEL); + + u32nLoops = 1; + switch (u32CoreSel) + { + // + // We need to compute the required number of ticks. To do so and to + // minimize divide operations, we'll use the following equation: + // u32Ticks = (u32NumUs * HFCR_EXACT)/1000000 + // = (u32NumUs * (HFCR_EXACT * 1024)/1000000) / 1024 + // The values for the variable u32ClkFreq are computed as follows: + // u32ClkFreq = (24390200 * 1024) / ((clksel+1)*1000000); + // (and we'll do the remaining divide by 1024, using a shift, later). + // + case 0: + u32ClkFreq = 24975; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 24975)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 24975)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 24975) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 1: + u32ClkFreq = 12487; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 12487)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 12487)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 12487) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 2: + u32ClkFreq = 8325; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 8325)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 8325)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 8325) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 3: + u32ClkFreq = 6243; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 6243)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 6243)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 6243) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 4: + u32ClkFreq = 4995; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4995)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4995)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 4995) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 5: + u32ClkFreq = 4162; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 4162)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 4162)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 4162) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 6: + u32ClkFreq = 3567; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3567)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3567)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 3567) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + case 7: + u32ClkFreq = 3121; + if ( u32NumUs > ((SYSTICK_MAX_TICKS / 3121)*1024) ) + { + u32nLoops = (u32NumUs / ((SYSTICK_MAX_TICKS / 3121)*1024)) + 1; + u32NumUs /= u32nLoops; + } + if ( u32NumUs > (MAX_U32 / 3121) ) + { + u32Ticks = (u32NumUs >> 10) * u32ClkFreq; + } + else + { + u32Ticks = (u32NumUs * u32ClkFreq) >> 10; + } + break; + default: + u32Ticks = 1; + break; + } // switch() + + uRet = u32Ticks * u32nLoops; + while ( u32nLoops-- ) + { + am_hal_systick_wait_ticks(u32Ticks); + } + + return uRet; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_systick.h b/bsp/apollo2/libraries/drivers/hal/am_hal_systick.h new file mode 100644 index 0000000000..bd5e576938 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_systick.h @@ -0,0 +1,83 @@ +//***************************************************************************** +// +// am_hal_systick.h +//! @file +//! +//! @brief Functions for accessing and configuring the SYSTICK. +//! +//! @addtogroup systick2 System Timer (SYSTICK) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_SYSTICK_H +#define AM_HAL_SYSTICK_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_systick_start(void); +extern void am_hal_systick_stop(void); +extern void am_hal_systick_int_enable(void); +extern void am_hal_systick_int_disable(void); +extern uint32_t am_hal_systick_int_status_get(void); +extern void am_hal_systick_reset(void); +extern void am_hal_systick_load(uint32_t ui32LoadVal); +extern uint32_t am_hal_systick_count(void); +extern uint32_t am_hal_systick_wait_ticks(uint32_t u32Ticks); +extern uint32_t am_hal_systick_delay_us(uint32_t u32NumUs); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_SYSTICK_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.c b/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.c new file mode 100644 index 0000000000..722f22fa13 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.c @@ -0,0 +1,381 @@ +//***************************************************************************** +// +// am_hal_tpiu.c +//! @file +//! +//! @brief Support functions for the ARM TPIU module +//! +//! Provides support functions for configuring the ARM TPIU module +//! +//! @addtogroup tpiu2 Trace Port Interface Unit (TPIU) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Enable the clock to the TPIU module. +//! +//! This function enables the clock to the TPIU module. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_clock_enable(void) +{ + // + // Enable the TPIU clock + // + AM_REG(MCUCTRL, TPIUCTRL) |= AM_REG_MCUCTRL_TPIUCTRL_ENABLE_M; +} + +//***************************************************************************** +// +//! @brief Disable the clock to the TPIU module. +//! +//! This function disables the clock to the TPIU module. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_clock_disable(void) +{ + // + // Disable the TPIU clock + // + AM_REG(MCUCTRL, TPIUCTRL) &= ~AM_REG_MCUCTRL_TPIUCTRL_ENABLE_M; +} + +//***************************************************************************** +// +//! @brief Set the output port width of the TPIU +//! +//! @param ui32PortWidth - The desired port width (in bits) +//! +//! This function uses the TPIU_CSPSR register to set the desired output port +//! width of the TPIU. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_port_width_set(uint32_t ui32PortWidth) +{ + AM_REG(TPIU, CSPSR) = 1 << (ui32PortWidth - 1); +} + +//***************************************************************************** +// +//! @brief Read the supported_output port width of the TPIU +//! +//! This function uses the \e TPIU_SSPSR register to set the supported output +//! port widths of the TPIU. +//! +//! @return Current width of the TPIU output port +// +//***************************************************************************** +uint32_t +am_hal_tpiu_supported_port_width_get(void) +{ + uint32_t i, ui32WidthValue; + + // + // Read the supported width register. + // + ui32WidthValue = AM_REG(TPIU, SSPSR); + + // + // The register value is encoded in a one-hot format, so the position of + // the single set bit determines the actual width of the port. + // + for (i = 1; i < 32; i++) + { + // + // Check each bit for a '1'. When we find it, our current loop index + // will be equal to the port width. + // + if (ui32WidthValue == (0x1 << (i - 1))) + { + return i; + } + } + + // + // We should never get here, but if we do, just return the smallest + // possible value for a supported trace port width. + // + return 1; +} + +//***************************************************************************** +// +//! @brief Read the output port width of the TPIU +//! +//! This function uses the \e TPIU_CSPSR register to set the desired output +//! port width of the TPIU. +//! +//! @return Current width of the TPIU output port +// +//***************************************************************************** +uint32_t +am_hal_tpiu_port_width_get(void) +{ + uint32_t ui32Temp; + uint32_t ui32Width; + + ui32Width = 1; + ui32Temp = AM_REG(TPIU, CSPSR); + + while ( !(ui32Temp & 1) ) + { + ui32Temp = ui32Temp >> 1; + ui32Width++; + + if (ui32Width > 32) + { + ui32Width = 0; + break; + } + } + + // + // Current width of the TPIU output port. + // + return ui32Width; +} + +//***************************************************************************** +// +//! @brief Configure the TPIU based on the values in the configuration struct. +//! +//! @param psConfig - pointer to an am_hal_tpiu_config_t structure containing +//! the desired configuration information. +//! +//! This function reads the provided configuration structure, and sets the +//! relevant TPIU registers to achieve the desired configuration. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_configure(am_hal_tpiu_config_t *psConfig) +{ + // + // Set the clock freq in the MCUCTRL register. + // + AM_REG(MCUCTRL, TPIUCTRL) |= psConfig->ui32TraceClkIn; + + // + // Set the desired protocol. + // + AM_REG(TPIU, SPPR) = psConfig->ui32PinProtocol; + + // + // Set the parallel port width. This may be redundant if the user has + // selected a serial protocol, but we'll set it anyway. + // + AM_REG(TPIU, CSPSR) = (1 << (psConfig->ui32ParallelPortSize - 1)); + + // + // Set the clock prescaler. + // + AM_REG(TPIU, ACPR) = psConfig->ui32ClockPrescaler; +} + +//***************************************************************************** +// +//! @brief Enables the TPIU +//! +//! This function enables the ARM TPIU by setting the TPIU registers and then +//! enabling the TPIU clock source in MCU control register. +//! +//! @param psConfig - structure for configuration. +//! If ui32SetItmBaud, the other structure members are used to set the +//! TPIU configuration. +//! But for simplicity, ui32SetItmBaud can be set to one of the +//! following, in which case all other structure members are ignored. +//! In this case, the given BAUD rate is based on a div-by-8 HFRC clock. +//! AM_HAL_TPIU_BAUD_57600 +//! AM_HAL_TPIU_BAUD_115200 +//! AM_HAL_TPIU_BAUD_230400 +//! AM_HAL_TPIU_BAUD_460800 +//! AM_HAL_TPIU_BAUD_500000 +//! AM_HAL_TPIU_BAUD_1M +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_enable(am_hal_tpiu_config_t *psConfig) +{ + uint32_t ui32HFRC, ui32SWOscaler, ui32ITMbitrate; + + ui32ITMbitrate = psConfig->ui32SetItmBaud; + + // + // TPIU formatter & flush control register. + // + AM_REG(TPIU, FFCR) = 0; + + if ( ui32ITMbitrate ) + { + // + // Set the Current Parallel Port Size (note - only 1 bit can be set). + // + AM_REG(TPIU, CSPSR) = AM_REG_TPIU_CSPSR_CWIDTH_1BIT; + + // + // Use some default assumptions to set the ITM frequency. + // + if ( (ui32ITMbitrate < AM_HAL_TPIU_BAUD_57600 ) || + (ui32ITMbitrate > AM_HAL_TPIU_BAUD_2M ) ) + { + ui32ITMbitrate = AM_HAL_TPIU_BAUD_DEFAULT; + } + + // + // Get the current HFRC frequency. + // + ui32HFRC = am_hal_clkgen_sysclk_get(); + + // + // Compute the SWO scaler value. + // + if ( ui32HFRC != 0xFFFFFFFF ) + { + ui32SWOscaler = ((ui32HFRC / 8) / ui32ITMbitrate) - 1; + } + else + { + ui32SWOscaler = ( (AM_HAL_CLKGEN_FREQ_MAX_HZ / 8) / + AM_HAL_TPIU_BAUD_DEFAULT ) - 1; + } + + // + // Set the scaler value. + // + AM_REG(TPIU, ACPR) = AM_REG_TPIU_ACPR_SWOSCALER(ui32SWOscaler); + + // + // Set for UART mode + // + AM_REG(TPIU, SPPR) = AM_REG_TPIU_SPPR_TXMODE_UART; + + // + // Make sure we are not in test mode (important for proper deep sleep + // operation). + // + AM_REG(TPIU, ITCTRL) = AM_REG_TPIU_ITCTRL_MODE_NORMAL; + + // + // Enable the TPIU clock source in MCU control. + // Set TPIU clock for HFRC/8 (6 or 3 MHz) operation. + // + AM_REGn(MCUCTRL, 0, TPIUCTRL) = + AM_REG_MCUCTRL_TPIUCTRL_CLKSEL_HFRC_DIV_8 | + AM_REG_MCUCTRL_TPIUCTRL_ENABLE_EN; + } + else + { + // + // Set the configuration according to the structure values. + // + + // + // Set the Asynchronous Clock Prescaler Register. + // + AM_REG(TPIU, ACPR) = psConfig->ui32ClockPrescaler; + + // + // Set the Selected Pin Protocol Register. + // e.g. AM_REG_TPIU_SPPR_TXMODE_UART + // + AM_REG(TPIU, SPPR) = psConfig->ui32PinProtocol; + + // + // Set the Current Parallel Port Size (note - only 1 bit can be set). + // This may be redundant if the user has selected a serial protocol, + // but we'll set it anyway. + // + AM_REG(TPIU, CSPSR) = (1 << (psConfig->ui32ParallelPortSize - 1)); + + // + // Set the clock freq in the MCUCTRL register. + // + AM_REG(MCUCTRL, TPIUCTRL) |= psConfig->ui32TraceClkIn; + } + + // + // Wait for 50us for the data to flush out. + // + am_hal_itm_delay_us(50); +} + +//***************************************************************************** +// +//! @brief Disables the TPIU +//! +//! This function disables the ARM TPIU by disabling the TPIU clock source +//! in MCU control register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_tpiu_disable(void) +{ + // + // Disable the TPIU clock source in MCU control. + // + AM_REG(MCUCTRL, TPIUCTRL) = AM_REG_MCUCTRL_TPIUCTRL_CLKSEL_0MHz | + AM_REG_MCUCTRL_TPIUCTRL_ENABLE_DIS; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.h b/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.h new file mode 100644 index 0000000000..9739034a18 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_tpiu.h @@ -0,0 +1,193 @@ +//***************************************************************************** +// +// am_hal_tpiu.h +//! @file +//! +//! @brief Definitions and structures for working with the TPIU. +//! +//! @addtogroup tpiu2 Trace Port Interface Unit (TPIU) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_TPIU_H +#define AM_HAL_TPIU_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// TPIU bit rate defines. +// +//***************************************************************************** +#define AM_HAL_TPIU_BAUD_57600 (115200 / 2) +#define AM_HAL_TPIU_BAUD_115200 (115200 * 1) +#define AM_HAL_TPIU_BAUD_230400 (115200 * 2) +#define AM_HAL_TPIU_BAUD_460800 (115200 * 4) +#define AM_HAL_TPIU_BAUD_500000 (1000000 / 2) +#define AM_HAL_TPIU_BAUD_1M (1000000 * 1) +#define AM_HAL_TPIU_BAUD_2M (1000000 * 2) +#define AM_HAL_TPIU_BAUD_DEFAULT (AM_HAL_TPIU_BAUD_1M) + +//***************************************************************************** +// +// TPIU register defines. +// +//***************************************************************************** +#define AM_HAL_TPIU_SSPSR 0xE0040000 //! Supported Parallel Port Sizes +#define AM_HAL_TPIU_CSPSR 0xE0040004 //! Current Parallel Port Size +#define AM_HAL_TPIU_ACPR 0xE0040010 //! Asynchronous Clock Prescaler +#define AM_HAL_TPIU_SPPR 0xE00400F0 //! Selected Pin Protocol +#define AM_HAL_TPIU_TYPE 0xE0040FC8 //! TPIU Type + +//***************************************************************************** +// +// TPIU ACPR defines. +// +//***************************************************************************** +#define AM_HAL_TPIU_ACPR_SWOSCALER_M 0x0000FFFF //! SWO baud rate prescalar + +//***************************************************************************** +// +// TPIU_SPPR TXMODE defines. +// +//***************************************************************************** +#define AM_HAL_TPIU_SPPR_PARALLEL 0x00000000 +#define AM_HAL_TPIU_SPPR_MANCHESTER 0x00000001 +#define AM_HAL_TPIU_SPPR_NRZ 0x00000002 + +//***************************************************************************** +// +// TPIU Type defines +// +//***************************************************************************** +#define AM_HAL_TPIU_TYPE_NRZVALID 0x00000800 +#define AM_HAL_TPIU_TYPE_MANCVALID 0x00000400 +#define AM_HAL_TPIU_TYPE_PTINVALID 0x00000200 +#define AM_HAL_TPIU_TYPE_FIFOSZ_M 0x000001C0 + +//***************************************************************************** +// +// TPIU Clock defines +// +//***************************************************************************** +#define AM_HAL_TPIU_TRACECLKIN_6MHZ AM_REG_MCUCTRL_TPIUCTRL_TPIUCLKSEL(0) +#define AM_HAL_TPIU_TRACECLKIN_3MHZ AM_REG_MCUCTRL_TPIUCTRL_TPIUCLKSEL(1) +#define AM_HAL_TPIU_TRACECLKIN_1_5MHZ AM_REG_MCUCTRL_TPIUCTRL_TPIUCLKSEL(2) +#define AM_HAL_TPIU_TRACECLKIN_750KHZ AM_REG_MCUCTRL_TPIUCTRL_TPIUCLKSEL(3) + +//***************************************************************************** +// +//! @brief Structure used for configuring the TPIU +// +//***************************************************************************** +typedef struct +{ + // + // If ui32SetItmBaud is non-zero, the ITM frequency is set to the given + // frequency, and is based on a divide-by-8 HFRC TPIU clock. + // If zero, other structure members are used to set the TPIU configuration. + // + uint32_t ui32SetItmBaud; + + // + //! MCU Control TRACECLKIN clock freq. + //! + //! Valid values for ui32TraceClkIn are: + //! + //! AM_HAL_TPIU_TRACECLKIN_6MHZ + //! AM_HAL_TPIU_TRACECLKIN_3MHZ + //! AM_HAL_TPIU_TRACECLKIN_1_5MHZ + //! AM_HAL_TPIU_TRACECLKIN_750KHZ + // + uint32_t ui32TraceClkIn; + + // + //! Protocol to use for the TPIU + //! + //! Valid values for ui32PinProtocol are: + //! + //! AM_HAL_TPIU_SPPR_PARALLEL + //! AM_HAL_TPIU_SPPR_MANCHESTER + //! AM_HAL_TPIU_SPPR_NRZ + // + uint32_t ui32PinProtocol; + + // + //! Desired width of the TPIU parallel port + // + uint32_t ui32ParallelPortSize; + + // + //! Desired Clock prescaler value + // + uint32_t ui32ClockPrescaler; +} +am_hal_tpiu_config_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_tpiu_clock_enable(void); +extern void am_hal_tpiu_clock_disable(void); +extern void am_hal_tpiu_port_width_set(uint32_t ui32PortWidth); +extern uint32_t am_hal_tpiu_supported_port_width_get(void); +extern uint32_t am_hal_tpiu_port_width_get(void); +extern void am_hal_tpiu_configure(am_hal_tpiu_config_t *psConfig); +extern void am_hal_tpiu_enable(am_hal_tpiu_config_t *psConfig); +extern void am_hal_tpiu_disable(void); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_TPIU_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_ttp.c b/bsp/apollo2/libraries/drivers/hal/am_hal_ttp.c new file mode 100644 index 0000000000..77bde67b87 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_ttp.c @@ -0,0 +1,205 @@ +//***************************************************************************** +// +// am_hal_ttp.c +//! @file +//! +//! @brief Functions for handling the "two time program" interface. +//! +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#include "am_mcu_apollo.h" +#include "am_hal_ttp.h" + +//***************************************************************************** +// +// Local constants +// +//***************************************************************************** +#define TTP_ADDR 0x50020000 + +//***************************************************************************** +// +// Local prototypes +// +//***************************************************************************** +#if !defined(__GNUC__) +void __breakpoint(int val); +#endif + +//***************************************************************************** +// +// A function to verify that the TTP was saved and/or restored properly. +// +//***************************************************************************** +int +verifyTTPSaved(uint32_t *pSaveArray, int iNumWords) +{ + int ix, iErrCnt = 0; + uint32_t *pDataSpace = (uint32_t*)TTP_ADDR; + + for (ix = 0; ix +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Transmit and receive queue pointers for each UART module. +// +//***************************************************************************** +am_hal_queue_t g_psTxQueue[AM_REG_UART_NUM_MODULES]; +am_hal_queue_t g_psRxQueue[AM_REG_UART_NUM_MODULES]; + +//***************************************************************************** +// +// Power tracking structure +// +//***************************************************************************** +am_hal_uart_pwrsave_t am_hal_uart_pwrsave[AM_REG_UART_NUM_MODULES]; + +//***************************************************************************** +// +// Set Baud Rate based on the UART clock frequency. +// +//***************************************************************************** + +#define BAUDCLK (32) + +static void +config_baudrate(uint32_t ui32Module, uint32_t ui32Baudrate, uint32_t ui32UartClkFreq) +{ + uint64_t ui64FractionDivisorLong; + uint64_t ui64IntermediateLong; + uint32_t ui32IntegerDivisor; + uint32_t ui32FractionDivisor; + uint32_t ui32BaudClk; + + // + // Calculate register values. + // + ui32BaudClk = BAUDCLK * ui32Baudrate; + ui32IntegerDivisor = (uint32_t)(ui32UartClkFreq / ui32BaudClk); + ui64IntermediateLong = (ui32UartClkFreq * 64) / ui32BaudClk; + ui64FractionDivisorLong = ui64IntermediateLong - (ui32IntegerDivisor * 64); + ui32FractionDivisor = (uint32_t)ui64FractionDivisorLong; + + // + // Check the result. + // + am_hal_debug_assert_msg(ui32IntegerDivisor > 0, "Integer divisor MUST be greater than or equal to 1."); + + // + // Write the UART regs. + // + AM_REGn(UART, ui32Module, IBRD) = ui32IntegerDivisor; + AM_REGn(UART, ui32Module, IBRD) = ui32IntegerDivisor; + AM_REGn(UART, ui32Module, FBRD) = ui32FractionDivisor; +} + +//***************************************************************************** +// +//! @brief Set up the UART. +//! +//! @param psConfig pointer to a structure that holds the settings for the UART. +//! @param ui32UartclkFreq is clock frequency that the UART is running at. +//! +//! This function should be used to perform the initial set-up of the UART. +//! +//! @return none. +// +//***************************************************************************** +void +am_hal_uart_config(uint32_t ui32Module, am_hal_uart_config_t *psConfig) + +{ + uint32_t ui32ConfigVal = 0; + + // + // Configure the Baudrate. + // + config_baudrate(ui32Module, psConfig->ui32BaudRate, am_hal_clkgen_sysclk_get()); + + // + // OR in the Data bits. + // + ui32ConfigVal |= psConfig->ui32DataBits; + + // + // OR in the Two Stop bit if used. + // + ui32ConfigVal |= psConfig->bTwoStopBits ? AM_REG_UART_LCRH_STP2_M : 0; + + // + // OR in the Parity. + // + ui32ConfigVal |= psConfig->ui32Parity; + + // + // Write config to Line control register. + // + AM_REGn(UART, ui32Module, LCRH) |= ui32ConfigVal; + + // + // Write the flow control settings to the control register. + // + AM_REGn(UART, ui32Module, CR) |= psConfig->ui32FlowCtrl; + + // + // Set the clock select field for 24MHz from the HFRC + // + AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKSEL_24MHZ; +} + +//***************************************************************************** +// +//! @brief Gets the status. +//! +//! This function returns the current status. +//! +//! @return current status. +// +//***************************************************************************** +uint32_t +am_hal_uart_status_get(uint32_t ui32Module) +{ + // + // Read and return the Status. + // + return AM_REGn(UART, ui32Module, RSR); +} + +//***************************************************************************** +// +//! @brief Gets the interrupt status. +//! +//! @param bEnabledOnly - If true returns the enabled interrupt status. +//! +//! This function returns the masked or raw interrupt status. +//! +//! @return Bitwise representation of the current interrupt status. +//! +//! The return value will be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_UART_INT_OVER_RUN +//! AM_HAL_UART_INT_BREAK_ERR +//! AM_HAL_UART_INT_PARITY_ERR +//! AM_HAL_UART_INT_FRAME_ERR +//! AM_HAL_UART_INT_RX_TMOUT +//! AM_HAL_UART_INT_TX +//! AM_REG_UART_IER_TXIM_M +//! AM_HAL_UART_INT_RX +//! AM_HAL_UART_INT_DSRM +//! AM_HAL_UART_INT_DCDM +//! AM_HAL_UART_INT_CTSM +//! AM_HAL_UART_INT_RIM +// +//***************************************************************************** +uint32_t +am_hal_uart_int_status_get(uint32_t ui32Module, bool bEnabledOnly) +{ + if (bEnabledOnly) + { + // + // Read and return the Masked Interrupt Status. + // + return AM_REGn(UART, ui32Module, MIS); + } + else + { + // + // Read and return the Raw Interrupt Status. + // + return AM_REGn(UART, ui32Module, IES); + } +} + +//***************************************************************************** +// +//! @brief Clears the desired interrupts. +//! +//! @param ui32Interrupt - Interrupt bits to clear. +//! +//! This function clears the desired interrupts. +//! +//! ui32Interrupt should be a logical or of the following: +//! +//! AM_HAL_UART_INT_OVER_RUN +//! AM_HAL_UART_INT_BREAK_ERR +//! AM_HAL_UART_INT_PARITY_ERR +//! AM_HAL_UART_INT_FRAME_ERR +//! AM_HAL_UART_INT_RX_TMOUT +//! AM_HAL_UART_INT_TX +//! AM_REG_UART_IER_TXIM_M +//! AM_HAL_UART_INT_RX +//! AM_HAL_UART_INT_DSRM +//! AM_HAL_UART_INT_DCDM +//! AM_HAL_UART_INT_CTSM +//! AM_HAL_UART_INT_RIM +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_int_clear(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Clear the bits. + // + AM_REGn(UART, ui32Module, IEC) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Disables the desired interrupts. +//! +//! @param ui32Interrupt - Interrupt bits to disable. +//! +//! This function disables the desired interrupts. +//! +//! ui32Interrupt should be a logical or of the following: +//! +//! AM_HAL_UART_INT_OVER_RUN +//! AM_HAL_UART_INT_BREAK_ERR +//! AM_HAL_UART_INT_PARITY_ERR +//! AM_HAL_UART_INT_FRAME_ERR +//! AM_HAL_UART_INT_RX_TMOUT +//! AM_HAL_UART_INT_TX +//! AM_REG_UART_IER_TXIM_M +//! AM_HAL_UART_INT_RX +//! AM_HAL_UART_INT_DSRM +//! AM_HAL_UART_INT_DCDM +//! AM_HAL_UART_INT_CTSM +//! AM_HAL_UART_INT_RIM +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_int_disable(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Disable the bits. + // + AM_REGn(UART, ui32Module, IER) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Enables the desired interrupts. +//! +//! @param ui32Interrupt - Interrupt bits to enable. +//! +//! This function enables the desired interrupts. +//! +//! ui32Interrupt should be a logical or of the following: +//! +//! AM_HAL_UART_INT_OVER_RUN +//! AM_HAL_UART_INT_BREAK_ERR +//! AM_HAL_UART_INT_PARITY_ERR +//! AM_HAL_UART_INT_FRAME_ERR +//! AM_HAL_UART_INT_RX_TMOUT +//! AM_HAL_UART_INT_TX +//! AM_REG_UART_IER_TXIM_M +//! AM_HAL_UART_INT_RX +//! AM_HAL_UART_INT_DSRM +//! AM_HAL_UART_INT_DCDM +//! AM_HAL_UART_INT_CTSM +//! AM_HAL_UART_INT_RIM +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_int_enable(uint32_t ui32Module, uint32_t ui32Interrupt) +{ + // + // Enable the interrupts. + // + AM_REGn(UART, ui32Module, IER) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Returns the enabled interrupts. +//! +//! This function return the enabled interrupts. +//! +//! @return the enabled interrupts. This will be a logical or of the following: +//! +//! AM_HAL_UART_INT_OVER_RUN +//! AM_HAL_UART_INT_BREAK_ERR +//! AM_HAL_UART_INT_PARITY_ERR +//! AM_HAL_UART_INT_FRAME_ERR +//! AM_HAL_UART_INT_RX_TMOUT +//! AM_HAL_UART_INT_TX +//! AM_REG_UART_IER_TXIM_M +//! AM_HAL_UART_INT_RX +//! AM_HAL_UART_INT_DSRM +//! AM_HAL_UART_INT_DCDM +//! AM_HAL_UART_INT_CTSM +//! AM_HAL_UART_INT_RIM +//! +//! @return Returns the enabled interrupts. +// +//***************************************************************************** +uint32_t +am_hal_uart_int_enable_get(uint32_t ui32Module) +{ + // + // Return the enabled interrupts. + // + return AM_REGn(UART, ui32Module, IER); +} + +//***************************************************************************** +// +//! @brief Enable the UART, RX, and TX. +//! +//! This function enables the UART, RX, and TX. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_enable(uint32_t ui32Module) +{ + // + // Enable the UART, RX, and TX. + // + AM_REGan_SET(UART, ui32Module, CR, (AM_REG_UART_CR_UARTEN_M | + AM_REG_UART_CR_RXE_M | + AM_REG_UART_CR_TXE_M) ); +} + +//***************************************************************************** +// +//! @brief Disable the UART, RX, and TX. +//! +//! This function disables the UART, RX, and TX. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_disable(uint32_t ui32Module) +{ + // + // Disable the UART. + // + AM_REGan_CLR(UART, ui32Module, CR, (AM_REG_UART_CR_UARTEN_M | + AM_REG_UART_CR_RXE_M | + AM_REG_UART_CR_TXE_M) ); +} + +//***************************************************************************** +// +//! @brief Enable the UART in the power control block. +//! +//! This function enables the UART device in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_pwrctrl_enable(uint32_t ui32Module) +{ + // + // Check to make sure we're acting on a real UART module. + // + am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES, + "Trying to disable a UART module that doesn't exist"); + + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_UART0 << ui32Module); +} + +//***************************************************************************** +// +//! @brief Disable the UART in the power control block. +//! +//! This function disables the UART device in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_pwrctrl_disable(uint32_t ui32Module) +{ + // + // Check to make sure we're acting on a real UART module. + // + am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES, + "Trying to disable a UART module that doesn't exist"); + + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_UART0 << ui32Module); +} + +//***************************************************************************** +// +//! @brief Enable the UART in the power control block. +//! +//! This function enables the UART device in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_power_on_restore(uint32_t ui32Module) +{ + // + // Check to make sure we're acting on a real UART module. + // + am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES, + "Trying to enable a UART module that doesn't exist"); + + // + // Make sure this restore is a companion to a previous save call. + // + if ( am_hal_uart_pwrsave[ui32Module].bValid == 0 ) + { + return; + } + + // + // Enable power to the selected UART + // + am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_UART0 << ui32Module); + + // + // Restore the clock settings + // + am_hal_clkgen_uarten_set(ui32Module, am_hal_uart_pwrsave[ui32Module].UARTEN); + + // + // Restore the configuration registers from the global variable in SRAM. + // + AM_REGn(UART, ui32Module, ILPR) = am_hal_uart_pwrsave[ui32Module].ILPR; + AM_REGn(UART, ui32Module, IBRD) = am_hal_uart_pwrsave[ui32Module].IBRD; + AM_REGn(UART, ui32Module, FBRD) = am_hal_uart_pwrsave[ui32Module].FBRD; + AM_REGn(UART, ui32Module, LCRH) = am_hal_uart_pwrsave[ui32Module].LCRH; + AM_REGn(UART, ui32Module, CR) = am_hal_uart_pwrsave[ui32Module].CR; + AM_REGn(UART, ui32Module, IFLS) = am_hal_uart_pwrsave[ui32Module].IFLS; + AM_REGn(UART, ui32Module, IER) = am_hal_uart_pwrsave[ui32Module].IER; + + // + // Indicates we have restored the configuration. + // + am_hal_uart_pwrsave[ui32Module].bValid = 0; + + return; +} + +//***************************************************************************** +// +//! @brief Disable the UART in the power control block. +//! +//! This function disables the UART device in the power control block. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_power_off_save(uint32_t ui32Module) +{ + // + // Check to make sure we're acting on a real UART module. + // + am_hal_debug_assert_msg(ui32Module < AM_REG_UART_NUM_MODULES, + "Trying to disable a UART module that doesn't exist"); + + // + // Save all of the configuration register information for the selected + // UART. + // + am_hal_uart_pwrsave[ui32Module].ILPR = AM_REGn(UART, ui32Module, ILPR); + am_hal_uart_pwrsave[ui32Module].IBRD = AM_REGn(UART, ui32Module, IBRD); + am_hal_uart_pwrsave[ui32Module].FBRD = AM_REGn(UART, ui32Module, FBRD); + am_hal_uart_pwrsave[ui32Module].LCRH = AM_REGn(UART, ui32Module, LCRH); + am_hal_uart_pwrsave[ui32Module].CR = AM_REGn(UART, ui32Module, CR); + am_hal_uart_pwrsave[ui32Module].IFLS = AM_REGn(UART, ui32Module, IFLS); + am_hal_uart_pwrsave[ui32Module].IER = AM_REGn(UART, ui32Module, IER); + + // + // Save the clock setting and disable power to the selected UART. + // Save the current enable value. + // + am_hal_uart_pwrsave[ui32Module].UARTEN = + (AM_REG(CLKGEN, UARTEN) & AM_HAL_CLKGEN_UARTEN_UARTENn_M(ui32Module)) >> + AM_HAL_CLKGEN_UARTEN_UARTENn_S(ui32Module); + + // + // Disable the UART. + // + am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_DIS); + + // + // Indicates we have a valid saved configuration. + // + am_hal_uart_pwrsave[ui32Module].bValid = 1; + + // + // Disable power to the selected UART. + // + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_UART0 << ui32Module); + + return; +} + +//***************************************************************************** +// +//! @brief Enable the UART clock. +//! +//! This function enables the clock to the UART. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_clock_enable(uint32_t ui32Module) +{ + // + // Set CLKGEN.UARTEN, clear the field then write the desired enable value + // Valid enable values are DIS, EN, REDUCE_FREQ, EN_POWER_SAV. + // + am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_EN); + + // + // Enable the UART clock. + // + AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKEN_M; + + // + // Select default UART clock source + // + AM_REGn(UART, ui32Module, CR) |= AM_REG_UART_CR_CLKSEL_24MHZ; +} + +//***************************************************************************** +// +//! @brief Disable the UART clock. +//! +//! This function disables the clock to the UART. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_clock_disable(uint32_t ui32Module) +{ + // + // Disable the UART clock. + // + AM_REGn(UART, ui32Module, CR) &= ~AM_REG_UART_CR_CLKEN_M; + + // + // Disable the UART clock in the CLKGEN module. + // + am_hal_clkgen_uarten_set(ui32Module, AM_HAL_CLKGEN_UARTEN_DIS); +} + +//***************************************************************************** +// +//! @brief Set and enable the desired interrupt levels for the RX/TX fifo. +//! +//! @param ui32LvlCfg - Desired FIFO RX/TX levels. +//! +//! This function sets the desired interrupt levels for the RX/TX fifo and +//! enables the use of transmit and receive FIFO buffers. +//! +//! Valid values for ui32LvlCfg are: +//! +//! AM_HAL_UART_TX_FIFO_1_8 +//! AM_HAL_UART_TX_FIFO_1_4 +//! AM_HAL_UART_TX_FIFO_1_2 +//! AM_HAL_UART_TX_FIFO_3_4 +//! AM_HAL_UART_TX_FIFO_7_8 +//! +//! AM_HAL_UART_RX_FIFO_1_8 +//! AM_HAL_UART_RX_FIFO_1_4 +//! AM_HAL_UART_RX_FIFO_1_2 +//! AM_HAL_UART_RX_FIFO_3_4 +//! AM_HAL_UART_RX_FIFO_7_8 +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_fifo_config(uint32_t ui32Module, uint32_t ui32LvlCfg) +{ + // + // Enable the use of FIFOs. + // + AM_REGn(UART, ui32Module, LCRH) |= AM_REG_UART_LCRH_FEN_M; + + // + // Write the FIFO level register. + // + AM_REGn(UART, ui32Module, IFLS) = ui32LvlCfg; +} + +//***************************************************************************** +// +//! @brief Return the UART Flags. +//! +//! This function reads and returns the UART flags. +//! +//! @return Returns the Flags. +// +//***************************************************************************** +uint32_t +am_hal_uart_flags_get(uint32_t ui32Module) +{ + // + // Read and return the Flags. + // + return AM_REGn(UART, ui32Module, FR); +} + +//***************************************************************************** +// +//! @brief Outputs a single character using polling. +//! +//! @param cChar - Character to send. +//! +//! This function outputs a single character using polling. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_char_transmit_polled(uint32_t ui32Module, char cChar) +{ + // + // Wait for space, i.e. TX FIFO EMPTY + // + while (AM_BFRn(UART, ui32Module, FR, TXFF)); + + // + // Write the char. + // + AM_REGn(UART, ui32Module, DR) = cChar; +} + +//***************************************************************************** +// +//! @brief Outputs a zero terminated string using polling. +//! +//! @param pcString - Pointer to character string to send. +//! +//! This function outputs a zero terminated string using polling. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_string_transmit_polled(uint32_t ui32Module, char *pcString) +{ + while (*pcString) + { + // + // Wait for space, i.e. TX FIFO EMPTY. + // + while (AM_BFRn(UART, ui32Module, FR, TXFF)); + + // + // Write the char. + // + AM_REGn(UART, ui32Module, DR) = *pcString++; + } +} + +//***************************************************************************** +// +//! @brief Receives a character using polling. +//! +//! @param pcChar - Pointer to character to store received char. +//! +//! This function receives a character using polling. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_char_receive_polled(uint32_t ui32Module, char *pcChar) +{ + // + // Wait for data, i.e. RX FIFO NOT EMPTY. + // + while (AM_BFRn(UART, ui32Module, FR, RXFE)); + + // + // Save the char. + // + *pcChar = AM_REGn(UART, ui32Module, DR); +} + +//***************************************************************************** +// +//! @brief Receives one line using polling. +//! +//! @param ui32MaxChars - Maximum number of characters to receive. +//! @param pcChar - Pointer to character string to store received line. +//! +//! This function receives a line (delimited by '/n' or '/r') using polling. +//! Line buffer is 0 (NULL) terminated. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_line_receive_polled(uint32_t ui32Module, + uint32_t ui32MaxChars, + char *pcChar) +{ + char cRecChar; + uint32_t i; + + // + // Loop until we receive ui32MaxChars or receive a line ending. + // + for (i = 0; i < (ui32MaxChars - 1); i++) + { + // + // Get char. + // + am_hal_uart_char_receive_polled(ui32Module, &cRecChar); + + if ((cRecChar == '\n') || (cRecChar == '\r')) + { + // + // Zero terminate the buffer. + // + *pcChar = 0; + + return; + } + + *pcChar++ = cRecChar; + } +} + +//***************************************************************************** +// +//! @brief Initialize the buffered UART. +//! +//! @param pui8RxArray - Pointer to the RX buffer to fill. +//! @param ui32RxSize - size of RX buffer. +//! @param pui8TxArray - Pointer to the TX buffer to fill. +//! @param ui32TxSize - size of TX buffer. +//! +//! This function initializes the buffered UART. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_init_buffered(uint32_t ui32Module, + uint8_t *pui8RxArray, uint32_t ui32RxSize, + uint8_t *pui8TxArray, uint32_t ui32TxSize) +{ + // + // Enable the UART RX timeout interrupt. + // + AM_REGn(UART, ui32Module, IER) |= (AM_REG_UART_IES_RTRIS_M | + AM_REG_UART_IES_TXRIS_M); + + // + // Initialize the ring buffers. + // + am_hal_queue_init(&g_psTxQueue[ui32Module], pui8TxArray, 1, ui32TxSize); + am_hal_queue_init(&g_psRxQueue[ui32Module], pui8RxArray, 1, ui32RxSize); +} + +//***************************************************************************** +// +//! @brief Get the status of the buffered UART. +//! +//! @param pui32RxSize - Pointer to variable to return the Rx ring data size. +//! @param pui32TxSize - Pointer to variable to return the Tx ring data size. +//! +//! This function gets the status of the buffered UART. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_get_status_buffered(uint32_t ui32Module, + uint32_t *pui32RxSize, + uint32_t *pui32TxSize) +{ + // + // Return the current size of ring buffers. + // + if ( pui32RxSize ) + { + *pui32RxSize = am_hal_queue_data_left(&g_psRxQueue[ui32Module]); + } + + if ( pui32TxSize ) + { + *pui32TxSize = am_hal_queue_data_left(&g_psTxQueue[ui32Module]); + } +} + + +//***************************************************************************** +// +//! @brief Services the buffered UART. +//! +//! @param ui32Status is the contents of the UART interrupt status register. +//! +//! This function is responsible for servicing the buffered UART. Designed to +//! be called from the UART interrupt handler. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_uart_service_buffered(uint32_t ui32Module, uint32_t ui32Status) +{ + uint8_t ui8Character = '\x00'; + uint32_t ui32FifoEntry = 0; + + // + // Check to see if we have filled the Rx FIFO past the configured limit, or + // if we have an 'old' character or two sitting in the FIFO. + // + if (ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M)) + { + // + // While there's stuff in the RX fifo.... + // + while (!AM_BFRn(UART, ui32Module, FR, RXFE)) + { + // + // Read each character out one by one, and add it to the ring + // buffer. This will start losing bytes if the fifo ever overflows. + // + ui32FifoEntry = AM_REGn(UART, ui32Module , DR); + + // + // As long as no error bits were set, we should push this byte to + // the FIFO. + // + if ( (ui32FifoEntry & 0xF00) == 0 ) + { + ui8Character = ui32FifoEntry & 0xFF; + am_hal_queue_item_add(&g_psRxQueue[ui32Module], &ui8Character, 1); + } + } + } + + // + // Check to see if our TX buffer has been recently emptied. If so, we + // should refill it from the TX ring buffer. + // + if (ui32Status & AM_REG_UART_IES_TXRIS_M) + { + // + // Keep refilling until the fifo is full, or the ring buffer is empty, + // whichever happens first. + // + while (am_hal_queue_data_left(&g_psTxQueue[ui32Module]) && + !AM_BFRn(UART, ui32Module, FR, TXFF)) + { + am_hal_queue_item_get(&g_psTxQueue[ui32Module], &ui8Character, 1); + AM_REGn(UART, ui32Module , DR) = ui8Character; + } + } +} + +//***************************************************************************** +// +//! @brief Services the buffered UART. +//! +//! @param ui32Status is the contents of the UART interrupt status register. +//! +//! This function is responsible for servicing the buffered UART. Designed to +//! be called from the UART interrupt handler. +//! +//! This function behaves exactly like am_hal_uart_service_buffered() \e except +//! it does not completely empty the RX FIFO on every interrupt event. Instead, +//! it will leave at least one byte behind until it receives a UART RX TIMEOUT +//! interrupt. If you use this service routine, you can treat the RX TIMEOUT +//! interrupt as a UART IDLE interrupt. Every time the UART RX line goes IDLE +//! for 32 consecutive bit-times you WILL receive a UART RX TIMEOUT interrupt. +//! This behavior is not guaranteed for am_hal_uart_service_buffered(). +//! +//! @return None +// +//***************************************************************************** +void +am_hal_uart_service_buffered_timeout_save(uint32_t ui32Module, uint32_t ui32Status) +{ + uint8_t ui8Character = '\x00'; + uint32_t ui32Count = 0; + uint32_t ui32FifoEntry = 0; + + // + // Check to see if we have filled the Rx FIFO past the configured limit, or + // if we have an 'old' character or two sitting in the FIFO. + // + if (ui32Status & (AM_REG_UART_IES_RXRIS_M | AM_REG_UART_IES_RTRIS_M)) + { + // + // Check to see what our FIFO configuration setting is. + // + uint32_t ui32FifoThreshold; + uint32_t ui32FifoCfg = AM_BFMn(UART, ui32Module, IFLS, RXIFLSEL); + + // + // Compute the number of bytes for receive interrupt from the FIFO level + // register. + // + switch(ui32FifoCfg) + { + case AM_HAL_UART_RX_FIFO_1_8: ui32FifoThreshold = 4; break; + case AM_HAL_UART_RX_FIFO_1_4: ui32FifoThreshold = 8; break; + case AM_HAL_UART_RX_FIFO_1_2: ui32FifoThreshold = 16; break; + case AM_HAL_UART_RX_FIFO_3_4: ui32FifoThreshold = 24; break; + case AM_HAL_UART_RX_FIFO_7_8: ui32FifoThreshold = 28; break; + default: + ui32FifoThreshold = 32; + } + + // + // While there's stuff in the RX fifo.... + // + while (!AM_BFRn(UART, ui32Module, FR, RXFE)) + { + // + // Read each character out one by one, and add it to the ring + // buffer. This will start losing bytes if the fifo ever overflows. + // + ui32FifoEntry = AM_REGn(UART, ui32Module, DR); + + // + // As long as no error bits were set, we should push this byte to + // the FIFO. + // + if ( (ui32FifoEntry & 0xF00) == 0) + { + ui8Character = ui32FifoEntry & 0xFF; + am_hal_queue_item_add(&g_psRxQueue[ui32Module], &ui8Character, 1); + } + + // + // Leave one byte to trigger the RX timeout interrupt. + // + if ( ++ui32Count >= (ui32FifoThreshold - 1) ) + { + break; + } + } + } + + // + // Check to see if our TX buffer has been recently emptied. If so, we + // should refill it from the TX ring buffer. + // + if (ui32Status & AM_REG_UART_IES_TXRIS_M) + { + // + // Keep refilling until the fifo is full, or the ring buffer is empty, + // whichever happens first. + // + while (am_hal_queue_data_left(&g_psTxQueue[ui32Module]) && + !AM_BFRn(UART, ui32Module, FR, TXFF)) + { + am_hal_queue_item_get(&g_psTxQueue[ui32Module], &ui8Character, 1); + AM_REGn(UART, ui32Module , DR) = ui8Character; + } + } +} + +//***************************************************************************** +// +//! @brief Puts a char in the buffer or directly to the fifo if available. +//! +//! @param cChar - Character to send. +//! +//! This function puts a character in the buffer or directly to the fifo. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_char_transmit_buffered(uint32_t ui32Module, char cChar) +{ + // + // Check the status of the Tx fifo and the Tx ring buffer. + // + if (am_hal_queue_empty(&g_psTxQueue[ui32Module]) && + !AM_BFRn(UART, ui32Module, FR, TXFF)) + { + // + // If the fifo isn't full yet, and the ring buffer isn't being used, + // just write the new character directly to the fifo. + // + AM_REGn(UART, ui32Module, DR) = cChar; + } + else + { + // + // If we get here, either the fifo is full, or the ring buffer is + // already in use. In either case, we need to use the ring buffer + // to make sure that the transmitted data gets sent in the right + // order. If the buffer is already full, we will simply lose this + // byte. + // + am_hal_queue_item_add(&g_psTxQueue[ui32Module], &cChar, 1); + } +} + +//***************************************************************************** +// +//! @brief Puts a null terminaled string in the buffer or directly to the fifo. +//! +//! @param pcString - Pointer to buffer used for sending. +//! +//! This function puts a string in the buffer or directly to the fifo if there +//! is space available. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_uart_string_transmit_buffered(uint32_t ui32Module, char *pcString) +{ + // + // Check the status of the Tx fifo and the Tx ring buffer. + // + while (*pcString) + { + if (am_hal_queue_empty(&g_psTxQueue[ui32Module]) && + !AM_BFRn(UART, ui32Module, FR, TXFF)) + { + // + // If the fifo isn't full yet, and the ring buffer isn't being used, + // just write the new character directly to the fifo. + // + AM_REGn(UART, ui32Module, DR) = *pcString; + } + else + { + // + // If we get here, either the fifo is full, or the ring buffer is + // already in use. In either case, we need to use the ring buffer + // to make sure that the transmitted data gets sent in the right + // order. If the buffer is already full, we will simply lose this + // byte. + // + am_hal_queue_item_add(&g_psTxQueue[ui32Module], pcString, 1); + } + + // + // Move the pointer to the next character. + // + pcString++; + } +} + +//***************************************************************************** +// +//! @brief Returns n number of characters from the ring buffer or until empty. +//! +//! @param pcString - Pointer to buffer for putting received characters. +//! @param ui32MaxChars - Maximum number of characters to receive. +//! +//! This function puts a char string in the buffer. +//! +//! @return Returns the number of chars received. +// +//***************************************************************************** +uint32_t +am_hal_uart_char_receive_buffered(uint32_t ui32Module, + char *pcString, + uint32_t ui32MaxChars) +{ + uint32_t ui32NumChars = 0; + + // + // Loop until ui32MaxChars or until empty. + // + while (am_hal_queue_data_left(&g_psRxQueue[ui32Module]) && ui32MaxChars) + { + // + // Pull a char out of the ring buffer. + // + am_hal_queue_item_get(&g_psRxQueue[ui32Module], pcString, 1); + + // + // Subtract from ui32MaxChars. + // Add to ui32NumChars. + // Move pointer in buffer. + // + ui32MaxChars--; + ui32NumChars++; + pcString++; + } + + // + // return the number of chars received. + // + return ui32NumChars; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_uart.h b/bsp/apollo2/libraries/drivers/hal/am_hal_uart.h new file mode 100644 index 0000000000..4aab828582 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_uart.h @@ -0,0 +1,345 @@ +//***************************************************************************** +// +// am_hal_uart.h +//! @file +//! +//! @brief Functions for accessing and configuring the UART. +//! +//! @addtogroup uart2 UART +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_UART_H +#define AM_HAL_UART_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name UART Interrupts +//! @brief Macro definitions for UART FIFO levels. +//! +//! They may be used with the \e am_hal_uart_fifo_config() function. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_UART_INT_OVER_RUN AM_REG_UART_IER_OEIM_M +#define AM_HAL_UART_INT_BREAK_ERR AM_REG_UART_IER_BEIM_M +#define AM_HAL_UART_INT_PARITY_ERR AM_REG_UART_IER_PEIM_M +#define AM_HAL_UART_INT_FRAME_ERR AM_REG_UART_IER_FEIM_M +#define AM_HAL_UART_INT_RX_TMOUT AM_REG_UART_IER_RTIM_M +#define AM_HAL_UART_INT_TX AM_REG_UART_IER_TXIM_M +#define AM_HAL_UART_INT_RX AM_REG_UART_IER_RXIM_M +#define AM_HAL_UART_INT_DSRM AM_REG_UART_IER_DSRMIM_M +#define AM_HAL_UART_INT_DCDM AM_REG_UART_IER_DCDMIM_M +#define AM_HAL_UART_INT_CTSM AM_REG_UART_IER_CTSMIM_M +#define AM_HAL_UART_INT_TXCMP AM_REG_UART_IER_TXCMPMIM_M +//! @} + +//***************************************************************************** +// +//! @name UART FIFO Levels +//! @brief Macro definitions for RTV interrupt status bits. +//! +//! These macros correspond to the bits in the UART interrupt status register. +//! They may be used with any of the \e am_hal_uart_int_x() functions. +//! +//! @{ +// +//***************************************************************************** +//TX +#define AM_HAL_UART_TX_FIFO_1_8 AM_REG_UART_IFLS_TXIFLSEL(0) +#define AM_HAL_UART_TX_FIFO_1_4 AM_REG_UART_IFLS_TXIFLSEL(1) +#define AM_HAL_UART_TX_FIFO_1_2 AM_REG_UART_IFLS_TXIFLSEL(2) +#define AM_HAL_UART_TX_FIFO_3_4 AM_REG_UART_IFLS_TXIFLSEL(3) +#define AM_HAL_UART_TX_FIFO_7_8 AM_REG_UART_IFLS_TXIFLSEL(4) +// RX +#define AM_HAL_UART_RX_FIFO_1_8 AM_REG_UART_IFLS_RXIFLSEL(0) +#define AM_HAL_UART_RX_FIFO_1_4 AM_REG_UART_IFLS_RXIFLSEL(1) +#define AM_HAL_UART_RX_FIFO_1_2 AM_REG_UART_IFLS_RXIFLSEL(2) +#define AM_HAL_UART_RX_FIFO_3_4 AM_REG_UART_IFLS_RXIFLSEL(3) +#define AM_HAL_UART_RX_FIFO_7_8 AM_REG_UART_IFLS_RXIFLSEL(4) +//! @} + +//***************************************************************************** +// +//! @name UART Status Register +//! @brief Macro definitions for UART Status Register Bits. +//! +//! They may be used with the \e am_hal_uart_status_get() function. +//! +//! @{ +// +//***************************************************************************** +// This is the overrun error indicator. +#define AM_HAL_UART_RSR_OVERRUN_NOERR AM_REG_UART_RSR_OESTAT_NOERR +#define AM_HAL_UART_RSR_OVERRUN_ERROR AM_REG_UART_RSR_OESTAT_ERR + +// This is the break error indicator. +#define AM_HAL_UART_RSR_BREAK_NOERR AM_REG_UART_RSR_BESTAT_NOERR +#define AM_HAL_UART_RSR_BREAK_ERROR AM_REG_UART_RSR_BESTAT_ERR + +// This is the parity error indicator. +#define AM_HAL_UART_RSR_PARITY_NOERR AM_REG_UART_RSR_PESTAT_NOERR +#define AM_HAL_UART_RSR_PARITY_ERROR AM_REG_UART_RSR_PESTAT_ERR + +// This is the framing error indicator. +#define AM_HAL_UART_RSR_FRAME_ERROR_NOERR AM_REG_UART_RSR_FESTAT_NOERR +#define AM_HAL_UART_RSR_FRAME_ERROR_ERROR AM_REG_UART_RSR_FESTAT_ERR +//! @} + +//***************************************************************************** +// +//! @name UART Flag Register +//! @brief Macro definitions for UART Flag Register Bits. +//! +//! They may be used with the \e am_hal_uart_flags_get() function. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_UART_FR_RING AM_REG_UART_FR_RI_M +#define AM_HAL_UART_FR_TX_EMPTY AM_REG_UART_FR_TXFE_XMTFIFO_EMPTY +#define AM_HAL_UART_FR_RX_FULL AM_REG_UART_FR_RXFF_RCVFIFO_FULL +#define AM_HAL_UART_FR_TX_FULL AM_REG_UART_FR_TXFF_XMTFIFO_FULL +#define AM_HAL_UART_FR_RX_EMPTY AM_REG_UART_FR_RXFE_RCVFIFO_EMPTY +#define AM_HAL_UART_FR_BUSY AM_REG_UART_FR_BUSY_BUSY +#define AM_HAL_UART_FR_DCD_DETECTED AM_REG_UART_FR_DCD_DETECTED +#define AM_HAL_UART_FR_DSR_READY AM_REG_UART_FR_DSR_READY +#define AM_HAL_UART_FR_CTS AM_REG_UART_FR_CTS_M +//! @} + + +//***************************************************************************** +// +//! @name UART Config Macros +//! @brief Macro definitions for available Data bits. +//! +//! They may be used with the \e am_hal_uart_config_t structure used by \e +//! am_hal_uart_config(). +//! +//! @{ +// +//***************************************************************************** +//***************************************************************************** +// +// Data bits defines. +// +//***************************************************************************** +#define AM_HAL_UART_DATA_BITS_8 AM_REG_UART_LCRH_WLEN(3) +#define AM_HAL_UART_DATA_BITS_7 AM_REG_UART_LCRH_WLEN(2) +#define AM_HAL_UART_DATA_BITS_6 AM_REG_UART_LCRH_WLEN(1) +#define AM_HAL_UART_DATA_BITS_5 0 + +//***************************************************************************** +// +// Parity defines. +// +//***************************************************************************** +#define AM_HAL_UART_PARITY_NONE 0 +#define AM_HAL_UART_PARITY_ODD AM_REG_UART_LCRH_PEN_M +#define AM_HAL_UART_PARITY_EVEN AM_REG_UART_LCRH_PEN_M | \ + AM_REG_UART_LCRH_EPS_M + +//***************************************************************************** +// +// Flow control defines. +// +//***************************************************************************** +#define AM_HAL_UART_FLOW_CTRL_NONE 0 +#define AM_HAL_UART_FLOW_CTRL_RTS_CTS AM_REG_UART_CR_CTSEN_M | \ + AM_REG_UART_CR_RTSEN_M +//! @} + +//***************************************************************************** +// +//! UART configuration structure +// +//***************************************************************************** +typedef struct +{ + // + //! Desired Baudrate for the UART. + // + uint32_t ui32BaudRate; + + // + //! Number of data bits. + //! + //! Valid values for ui32DataBits are: + //! + //! AM_HAL_UART_DATA_BITS_8 + //! AM_HAL_UART_DATA_BITS_7 + //! AM_HAL_UART_DATA_BITS_6 + //! AM_HAL_UART_DATA_BITS_5 + // + uint32_t ui32DataBits; + + // + //! Use two stop bits. + // + bool bTwoStopBits; + + // + //! Parity. + //! + //! Valid values for ui32Parity are: + //! + //! AM_HAL_UART_PARITY_NONE + //! AM_HAL_UART_PARITY_ODD + //! AM_HAL_UART_PARITY_EVEN + // + uint32_t ui32Parity; + + // + //! Flow control. + //! + //! Valid values for ui32FlowCtrl are: + //! + //! AM_HAL_UART_FLOW_CTRL_NONE + //! AM_HAL_UART_FLOW_CTRL_RTS_CTS + // + uint32_t ui32FlowCtrl; +} +am_hal_uart_config_t; + +//***************************************************************************** +// +// Structure for containing information about the UART's configuration while +// it is powered down. +// +//***************************************************************************** +typedef struct +{ + uint32_t ILPR; + uint32_t IBRD; + uint32_t FBRD; + uint32_t LCRH; + uint32_t CR; + uint32_t IFLS; + uint32_t IER; + uint32_t UARTEN; + uint32_t bValid; +} +am_hal_uart_pwrsave_t; + +//***************************************************************************** +// +// Global Variables +// +//***************************************************************************** +extern am_hal_uart_pwrsave_t am_hal_uart_pwrsave[AM_REG_UART_NUM_MODULES]; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_uart_pwrctrl_enable(uint32_t ui32Module); +extern void am_hal_uart_pwrctrl_disable(uint32_t ui32Module); +extern void am_hal_uart_power_on_restore(uint32_t ui32Module); +extern void am_hal_uart_power_off_save(uint32_t ui32Module); +extern void am_hal_uart_config(uint32_t ui32Module, + am_hal_uart_config_t *psConfig); +extern uint32_t am_hal_uart_status_get(uint32_t ui32Module); +extern uint32_t am_hal_uart_int_status_get(uint32_t ui32Module, + bool bEnabledOnly); +extern void am_hal_uart_int_clear(uint32_t ui32Module, + uint32_t ui32Interrupt); +extern void am_hal_uart_int_disable(uint32_t ui32Module, + uint32_t ui32Interrupt); +extern void am_hal_uart_int_enable(uint32_t ui32Module, + uint32_t ui32Interrupt); +extern uint32_t am_hal_uart_int_enable_get(uint32_t ui32Module); +extern void am_hal_uart_enable(uint32_t ui32Module); +extern void am_hal_uart_disable(uint32_t ui32Module); +extern void am_hal_uart_clock_enable(uint32_t ui32Module); +extern void am_hal_uart_clock_disable(uint32_t ui32Module); +extern void am_hal_uart_fifo_config(uint32_t ui32Module, uint32_t ui32LvlCfg); +extern uint32_t am_hal_uart_flags_get(uint32_t ui32Module); + +// rx/tx polled +extern void am_hal_uart_char_transmit_polled(uint32_t ui32Module, + char cChar); +extern void am_hal_uart_string_transmit_polled(uint32_t ui32Module, + char *pcString); +extern void am_hal_uart_char_receive_polled(uint32_t ui32Module, + char *pcChar); +extern void am_hal_uart_line_receive_polled(uint32_t ui32Module, + uint32_t ui32MaxChars, + char *pcChar); + +// rx/tx buffered +extern void am_hal_uart_init_buffered(uint32_t ui32Module, + uint8_t *pui8RxArray, + uint32_t ui32RxSize, + uint8_t *pui8TxArray, + uint32_t ui32TxSize); +extern void am_hal_uart_get_status_buffered(uint32_t ui32Module, + uint32_t *pui32RxSize, + uint32_t *pui32TxSize); +extern void am_hal_uart_service_buffered(uint32_t ui32Module, + uint32_t ui32Status); + +extern void am_hal_uart_service_buffered_timeout_save(uint32_t ui32Module, + uint32_t ui32Status); +extern void am_hal_uart_char_transmit_buffered(uint32_t ui32Module, + char cChar); +extern void am_hal_uart_string_transmit_buffered(uint32_t ui32Module, + char *pcString); +extern uint32_t am_hal_uart_char_receive_buffered(uint32_t ui32Module, + char *pcString, + uint32_t ui32MaxChars); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_UART_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.c b/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.c new file mode 100644 index 0000000000..31e28855e4 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.c @@ -0,0 +1,287 @@ +//***************************************************************************** +// +// am_hal_vcomp.c +//! @file +//! +//! @brief Functions for operating the on-chip Voltage Comparator +//! +//! @addtogroup vcomp2 Voltage Comparator (VCOMP) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +//! @brief Configure the Voltage Comparator module. +//! +//! @param psConfig is a structure containing configuration information for the +//! voltage comparator. +//! +//! This function configures the positive and negative input signals for the +//! voltage comparator. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_config(const am_hal_vcomp_config_t *psConfig) +{ + // + // The configuration word should be a simple OR of the components of the + // configuration structure. + // + AM_REG(VCOMP, CFG) = (psConfig->ui32LevelSelect | + psConfig->ui32PosInput | + psConfig->ui32NegInput); +} + +//***************************************************************************** +// +//! @brief Set the Voltage Comparator DAC Level Select in Configuration Reg. +//! +//! @param ui32Level - DAC voltage selector (use macros enumerations) +//! +//! This function sets the DAC level select in the configuration register. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_dac_level_set(uint32_t ui32Level) +{ + // + // Insert the supplied level into the vcomp configuration register + // + AM_BFW(VCOMP, CFG, LVLSEL, ui32Level >> AM_REG_VCOMP_CFG_LVLSEL_S); +} + +//***************************************************************************** +// +//! @brief Read the state of the voltage comparator. +//! +//! This function extracts the comparator state from the status register. +//! +//! @return the voltage comparator state +// +//***************************************************************************** +bool +am_hal_vcomp_read(void) +{ + return (AM_BFR(VCOMP, STAT, CMPOUT) == 1); +} + +//***************************************************************************** +// +//! @brief Enable the voltage comparator. +//! +//! This function powers up the voltage comparator. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_enable(void) +{ + AM_REG(VCOMP, PWDKEY) = 0; +} + +//***************************************************************************** +// +//! @brief Disable the voltage comparator. +//! +//! This function powers down the voltage comparator. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_disable(void) +{ + AM_REG(VCOMP, PWDKEY) = AM_REG_VCOMP_PWDKEY_KEYVAL; +} + +//***************************************************************************** +// +//! @brief Read the state of the voltage comparator interrupt status bits. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! This function extracts the interrupt status bits and returns the raw or +//! only the enabled based on bEnabledOnly. +//! +//! @return Bitwise representation of the current interrupt status. +//! +//! The return value will be the logical OR of one or more of the following +//! values: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +// +//***************************************************************************** +uint32_t +am_hal_vcomp_int_status_get(bool bEnabledOnly) +{ + if (bEnabledOnly) + { + uint32_t u32RetVal = AM_REG(VCOMP, INTSTAT); + return u32RetVal & AM_REG(VCOMP, INTEN); + } + else + { + return AM_REG(VCOMP, INTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Set the state of the voltage comparator interrupt status bits. +//! +//! @param ui32Interrupt - interrupts to be set. +//! +//! This function sets the specified interrupt status bits. +//! +//! ui32Interrupt should be a logical or of: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_int_set(uint32_t ui32Interrupt) +{ + AM_REG(VCOMP, INTSET) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Clear the state of the voltage comparator interrupt status bits. +//! +//! @param ui32Interrupt - interrupts to be cleared. +//! +//! This function clears the specified interrupt status bits. +//! +//! ui32Interrupt should be a logical or of: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_int_clear(uint32_t ui32Interrupt) +{ + AM_REG(VCOMP, INTCLR) = ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Enable the voltage comparator interrupt status bits. +//! +//! @param ui32Interrupt - interrupts to be enabled. +//! +//! This function enables desired interrupt status bits. +//! +//! ui32Interrupt should be a logical or of: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_int_enable(uint32_t ui32Interrupt) +{ + AM_REG(VCOMP, INTEN) |= ui32Interrupt; +} + +//***************************************************************************** +// +//! @brief Return the enabled, voltage comparator interrupt status bits. +//! +//! This function returns the enabled interrupt status bits +//! +//! @return returns the enabled interrupt status bits. The return is a logical +//! or of: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +// +//***************************************************************************** +uint32_t +am_hal_vcomp_int_enable_get(void) +{ + return AM_REG(VCOMP, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable the voltage comparator interrupt status bits. +//! +//! @param ui32Interrupt - interrupts to be disabled. +//! +//! This function disables desired interrupt status bits. +//! +//! ui32Interrupt should be a logical or of: +//! +//! AM_HAL_VCOMP_INT_OUTHI +//! AM_HAL_VCOMP_INT_OUTLO +//! +//! @return None +// +//***************************************************************************** +void +am_hal_vcomp_int_disable(uint32_t ui32Interrupt) +{ + AM_REG(VCOMP, INTEN) &= ~ui32Interrupt; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.h b/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.h new file mode 100644 index 0000000000..a6ca991aae --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_vcomp.h @@ -0,0 +1,176 @@ +//***************************************************************************** +// +// am_hal_vcomp.h +//! @file +//! +//! @brief Functions for operating the on-chip Voltage Comparator +//! +//! @addtogroup vcomp2 Voltage Comparator (VCOMP) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_VCOMP_H +#define AM_HAL_VCOMP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! @name Positive Input Selection +//! @brief Use these macros to determine the positive input to the comparator. +//! @{ +// +//***************************************************************************** +#define AM_HAL_VCOMP_PSEL_VDDADJ AM_REG_VCOMP_CFG_PSEL_VDDADJ +#define AM_HAL_VCOMP_PSEL_VTEMP AM_REG_VCOMP_CFG_PSEL_VTEMP +#define AM_HAL_VCOMP_PSEL_VEXT1 AM_REG_VCOMP_CFG_PSEL_VEXT1 +#define AM_HAL_VCOMP_PSEL_VEXT2 AM_REG_VCOMP_CFG_PSEL_VEXT2 +//! @} + +//***************************************************************************** +// +//! @name Negative Input Selection +//! @brief Use these macros to determine the negative input to the comparator. +//! @{ +// +//***************************************************************************** +#define AM_HAL_VCOMP_NSEL_VREFEXT1 AM_REG_VCOMP_CFG_NSEL_VREFEXT1 +#define AM_HAL_VCOMP_NSEL_VREFEXT2 AM_REG_VCOMP_CFG_NSEL_VREFEXT2 +#define AM_HAL_VCOMP_NSEL_VREFEXT3 AM_REG_VCOMP_CFG_NSEL_VREFEXT3 +#define AM_HAL_VCOMP_NSEL_DAC_LEVEL AM_REG_VCOMP_CFG_NSEL_DAC +//! @} + +//***************************************************************************** +// +//! @name Negative Input DAC Selectioin +//! @brief Use these macros to determine the NSEL DAC voltage setting +//! @{ +// +//***************************************************************************** +#define AM_HAL_VCOMP_DAC_LVLSEL_0_58V AM_REG_VCOMP_CFG_LVLSEL_0P58V +#define AM_HAL_VCOMP_DAC_LVLSEL_0_77V AM_REG_VCOMP_CFG_LVLSEL_0P77V +#define AM_HAL_VCOMP_DAC_LVLSEL_0_97V AM_REG_VCOMP_CFG_LVLSEL_0P97V +#define AM_HAL_VCOMP_DAC_LVLSEL_1_16V AM_REG_VCOMP_CFG_LVLSEL_1P16V +#define AM_HAL_VCOMP_DAC_LVLSEL_1_35V AM_REG_VCOMP_CFG_LVLSEL_1P35V +#define AM_HAL_VCOMP_DAC_LVLSEL_1_55V AM_REG_VCOMP_CFG_LVLSEL_1P55V +#define AM_HAL_VCOMP_DAC_LVLSEL_1_74V AM_REG_VCOMP_CFG_LVLSEL_1P74V +#define AM_HAL_VCOMP_DAC_LVLSEL_1_93V AM_REG_VCOMP_CFG_LVLSEL_1P93V +#define AM_HAL_VCOMP_DAC_LVLSEL_2_13V AM_REG_VCOMP_CFG_LVLSEL_2P13V +#define AM_HAL_VCOMP_DAC_LVLSEL_2_32V AM_REG_VCOMP_CFG_LVLSEL_2P32V +#define AM_HAL_VCOMP_DAC_LVLSEL_2_51V AM_REG_VCOMP_CFG_LVLSEL_2P51V +#define AM_HAL_VCOMP_DAC_LVLSEL_2_71V AM_REG_VCOMP_CFG_LVLSEL_2P71V +#define AM_HAL_VCOMP_DAC_LVLSEL_2_90V AM_REG_VCOMP_CFG_LVLSEL_2P90V +#define AM_HAL_VCOMP_DAC_LVLSEL_3_09V AM_REG_VCOMP_CFG_LVLSEL_3P09V +#define AM_HAL_VCOMP_DAC_LVLSEL_3_29V AM_REG_VCOMP_CFG_LVLSEL_3P29V +#define AM_HAL_VCOMP_DAC_LVLSEL_3_48V AM_REG_VCOMP_CFG_LVLSEL_3P48V +//! @} + +//***************************************************************************** +// +//! @name Interrupt Status Bits +//! @brief Interrupt Status Bits for enable/disble use +//! +//! These macros may be used to set and clear interrupt bits +//! @{ +// +//***************************************************************************** +#define AM_HAL_VCOMP_INT_OUTHI AM_REG_VCOMP_INTEN_OUTHI_M +#define AM_HAL_VCOMP_INT_OUTLO AM_REG_VCOMP_INTEN_OUTLOW_M +//! @} + +//***************************************************************************** +// +//! @brief Configuration struct +// +//***************************************************************************** +typedef struct +{ + // + //! The DAC level setting + // + uint32_t ui32LevelSelect; + + // + //! The "positive" comparator input channel + //! + //! This channel is usually used as the signal to be monitored. + // + uint32_t ui32PosInput; + + // + //! The "negative" comparator input channel + //! + //! This channel is usually used as the reference signal. + // + uint32_t ui32NegInput; +} +am_hal_vcomp_config_t; + +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_vcomp_config(const am_hal_vcomp_config_t *psConfig); +extern void am_hal_vcomp_dac_level_set(uint32_t ui3Level); +extern bool am_hal_vcomp_read(void); +extern void am_hal_vcomp_enable(void); +extern void am_hal_vcomp_disable(void); +extern void am_hal_vcomp_int_enable(uint32_t ui32Interrupt); +extern uint32_t am_hal_vcomp_int_enable_get(void); +extern void am_hal_vcomp_int_disable(uint32_t ui32Interrupt); +extern void am_hal_vcomp_int_clear(uint32_t ui32Interrupt); +extern void am_hal_vcomp_int_set(uint32_t ui32Interrupt); +extern uint32_t am_hal_vcomp_int_status_get(bool bEnabledOnly); + +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_VCOMP_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.c b/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.c new file mode 100644 index 0000000000..4e80113fd1 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.c @@ -0,0 +1,454 @@ +//***************************************************************************** +// +// am_hal_wdt.c +//! @file +//! +//! @brief Hardware abstraction layer for the Watchdog Timer module. +//! +//! @addtogroup wdt2 Watchdog Timer (WDT) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** + +#include +#include +#include "am_mcu_apollo.h" + +//***************************************************************************** +// +// Adjacency check +// +// This is related to the timer read workaround. This macro checks to see if +// the two supplied count values are within one "tick" of eachother. It should +// still pass in the event of a timer rollover. The "B" read is assumed to +// follow the "A" read. The macro returns "TRUE" when the adjacent timer reads +// can be used. +// +//***************************************************************************** +#define adjacent(A, B) (((A) == (B)) || (((A) + 1) == (B)) || ((B) == 0)) + +//***************************************************************************** +// +//! @brief Configure the watchdog timer. +//! +//! @param psConfig - pointer to a configuration structure containing the +//! desired watchdog settings. +//! +//! This function will set the watchdog configuration register based on the +//! user's desired settings listed in the structure referenced by psConfig. If +//! the structure indicates that watchdog interrupts are desired, this function +//! will also set the interrupt enable bit in the configuration register. +//! +//! @note In order to actually receive watchdog interrupt and/or watchdog reset +//! events, the caller will also need to make sure that the watchdog interrupt +//! vector is enabled in the ARM NVIC, and that watchdog resets are enabled in +//! the reset generator module. Otherwise, the watchdog-generated interrupt and +//! reset events will have no effect. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_wdt_init(const am_hal_wdt_config_t *psConfig) +{ + uint32_t ui32ConfigVal; + uint16_t ui16IntCount, ui16ResetCount; + bool bResetEnabled = psConfig->ui32Config & AM_HAL_WDT_ENABLE_RESET; + bool bInterruptEnabled = psConfig->ui32Config & AM_HAL_WDT_ENABLE_INTERRUPT; + + // + // Read the desired settings from the psConfig structure. + // + ui16IntCount = psConfig->ui16InterruptCount; + ui16ResetCount = psConfig->ui16ResetCount; + + // + // Write the interrupt and reset count values to a temporary variable. + // + // Accept the passed Config value, but clear the Counts that we are about to set. + ui32ConfigVal = psConfig->ui32Config & ~(AM_REG_WDT_CFG_INTVAL_M | AM_REG_WDT_CFG_RESVAL_M); + ui32ConfigVal |= AM_WRITE_SM(AM_REG_WDT_CFG_INTVAL, ui16IntCount); + ui32ConfigVal |= AM_WRITE_SM(AM_REG_WDT_CFG_RESVAL, ui16ResetCount); + + // + // If interrupts should be enabled, set the appropriate bit in the + // temporary variable. Also, enable the interrupt in INTEN register in the + // watchdog module. + // + if ( bInterruptEnabled ) + { + // + // Enable the watchdog interrupt if the configuration calls for them. + // + AM_REGn(WDT, 0, INTEN) |= AM_REG_WDT_INTEN_WDT_M; + } + else + { + // + // Disable the watchdog interrupt if the configuration doesn't call for + // watchdog interrupts. + // + AM_REGn(WDT, 0, INTEN) &= ~AM_REG_WDT_INTEN_WDT_M; + } + + // + // If resets should be enabled, set the appropriate bit in the temporary + // variable. + // + if ( bResetEnabled ) + { + // + // Also enable watchdog resets in the reset module. + // + AM_REG(RSTGEN, CFG) |= AM_REG_RSTGEN_CFG_WDREN_M; + } + else + { + // + // Disable watchdog resets in the reset module. + // + AM_REG(RSTGEN, CFG) &= ~AM_REG_RSTGEN_CFG_WDREN_M; + } + + // + // Check for a user specified clock select. If none specified then + // set 128Hz. + // + if ( !(psConfig->ui32Config & AM_REG_WDT_CFG_CLKSEL_M) ) + { + ui32ConfigVal |= AM_REG_WDT_CFG_CLKSEL_128HZ; + } + + // + // Write the saved value to the watchdog configuration register. + // + AM_REGn(WDT, 0, CFG) = ui32ConfigVal; +} + +//***************************************************************************** +// +//! @brief Starts the watchdog timer. +//! +//! Enables the watchdog timer tick using the 'enable' bit in the watchdog +//! configuration register. This function does not perform any locking of the +//! watchdog timer, so it can be disabled or reconfigured later. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_wdt_start(void) +{ + // + // Make sure the watchdog timer is in the "reset" state, and then set the + // enable bit to start counting. + // + AM_REGn(WDT, 0, CFG) |= AM_REG_WDT_CFG_WDTEN_M; + AM_REGn(WDT, 0, RSTRT) |= AM_REG_WDT_RSTRT_RSTRT_KEYVALUE; + +} + +//***************************************************************************** +// +//! @brief Stops the watchdog timer. +//! +//! Disables the watchdog timer tick by clearing the 'enable' bit in the +//! watchdog configuration register. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_wdt_halt(void) +{ + + // + // Clear the watchdog enable bit. + // + AM_REGn(WDT, 0, CFG) &= ~AM_REG_WDT_CFG_WDTEN_M; +} + +//***************************************************************************** +// +//! @brief Locks the watchdog configuration and starts the watchdog timer. +//! +//! This function sets the watchdog "lock" register, which prevents software +//! from re-configuring the watchdog. This action will also set the enable bit +//! for the watchdog timer, so it will start counting immediately. +//! +//! @return None. +// +//***************************************************************************** +void +am_hal_wdt_lock_and_start(void) +{ + // + // Write the 'key' value to the watchdog lock register. + // + AM_REGn(WDT, 0, LOCK) = AM_REG_WDT_LOCK_LOCK_KEYVALUE; +} + +//***************************************************************************** +// +//! @brief Read the state of the wdt interrupt status. +//! +//! @param bEnabledOnly - return the status of only the enabled interrupts. +//! +//! This function extracts the interrupt status bits and returns the enabled or +//! raw based on bEnabledOnly. +//! +//! @return WDT interrupt status. +// +//***************************************************************************** +uint32_t +am_hal_wdt_int_status_get(bool bEnabledOnly) +{ + if (bEnabledOnly) + { + uint32_t u32RetVal = AM_REG(WDT, INTSTAT); + return u32RetVal & AM_REG(WDT, INTEN); + } + else + { + return AM_REG(WDT, INTSTAT); + } +} + +//***************************************************************************** +// +//! @brief Set the state of the wdt interrupt status bit. +//! +//! This function sets the interrupt bit. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_wdt_int_set(void) +{ + AM_REG(WDT, INTSET) = AM_REG_WDT_INTSET_WDT_M; +} + +//***************************************************************************** +// +//! @brief Clear the state of the wdt interrupt status bit. +//! +//! This function clear the interrupt bit. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_wdt_int_clear(void) +{ + AM_REGn(WDT, 0, INTCLR) = AM_REG_WDT_INTCLR_WDT_M; +} + +//***************************************************************************** +// +//! @brief Enable the wdt interrupt. +//! +//! This function enable the interrupt. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_wdt_int_enable(void) +{ + AM_REG(WDT, INTEN) |= AM_REG_WDT_INTSET_WDT_M; +} + +//***************************************************************************** +// +//! @brief Return the enabled WDT interrupts. +//! +//! This function returns the enabled WDT interrupts. +//! +//! @return enabled WDT interrupts. +// +//***************************************************************************** +uint32_t +am_hal_wdt_int_enable_get(void) +{ + return AM_REG(WDT, INTEN); +} + +//***************************************************************************** +// +//! @brief Disable the wdt interrupt. +//! +//! This function disablee the interrupt. +//! +//! @return None +// +//***************************************************************************** +void +am_hal_wdt_int_disable(void) +{ + AM_REG(WDT, INTEN) &= ~AM_REG_WDT_INTSET_WDT_M; +} + +//***************************************************************************** +// +// Static function for reading the WDT counter value. +// +//***************************************************************************** +#if defined(__GNUC_STDC_INLINE__) +__attribute__((naked)) +static +void +back2back_read_asm(uint32_t *pui32Array, uint32_t *pui32Register) +{ + // pui32Array[] is a pointer to a 3 word data array provided by the caller. + // pui32Register = address of the timer to be read. + __asm + ( + // Do 3 back-to-back reads of the register + " ldr r2, [r1, #0]\n" // Get counter register value + " ldr r3, [r1, #0]\n" // Get counter register value again + " ldr r1, [r1, #0]\n" // Get counter register value for a third time + " str r2, [r0, #0]\n" // Store register value to variable + " str r3, [r0, #4]\n" // Store register value to variable + " str r1, [r0, #8]\n" // Store register value to variable + " bx lr\n" + ); +} + +#elif defined(__ARMCC_VERSION) +__asm static uint32_t +back2back_read_asm(uint32_t *pui32Array, uint32_t *pui32Register) +{ + ldr r2, [r1, #0] // Get TMRn register value + ldr r3, [r1, #0] // Get TMRn register value again + ldr r1, [r1, #0] // Get TMRn register value for a third time + str r2, [r0, #0] // Store register value to variable + str r3, [r0, #4] // Store register value to variable + str r1, [r0, #8] // Store register value to variable + bx lr +} + +#elif defined(__IAR_SYSTEMS_ICC__) +#pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing + // return statement on a non-void function +__stackless static uint32_t +back2back_read_asm(uint32_t *pui32Array, uint32_t *pui32Register) +{ + __asm(" ldr r2, [r1, #0]"); // Get TMRn register value + __asm(" ldr r3, [r1, #0]"); // Get TMRn register value again + __asm(" ldr r1, [r1, #0]"); // Get TMRn register value for a third time + __asm(" str r2, [r0, #0]"); // Store register value to variable + __asm(" str r3, [r0, #4]"); // Store register value to variable + __asm(" str r1, [r0, #8]"); // Store register value to variable + __asm(" bx lr"); +} +#pragma diag_default = Pe940 // Restore IAR compiler warning +#endif + + +//***************************************************************************** +// +//! @brief Get the wdt counter value. +//! +//! This function reads the current value of watch dog timer counter register. +//! +//! WARNING caller is responsible for masking interrutps before calling this +//! function. +//! +//! @return None +// +//***************************************************************************** +uint32_t +am_hal_wdt_counter_get(void) +{ + uint32_t ui32Values[3] = {0}; + uint32_t ui32Value; + + // + // First, go read the value from the counter register 3 times + // back to back in assembly language. + // + back2back_read_asm(ui32Values, (uint32_t *)AM_REG_WDTn(0)); + + // + // Now, we'll figure out which of the three values is the correct time. + // + if (ui32Values[0] == ui32Values[1]) + { + // + // If the first two values match, then neither one was a bad read. + // We'll take this as the current time. + // + ui32Value = ui32Values[1]; + } + else + { + // + // If the first two values didn't match, then one of them might be bad. + // If one of the first two values is bad, then the third one should + // always be correct. We'll take the third value as the correct count. + // + ui32Value = ui32Values[2]; + + // + // If all of the statements about the architecture are true, the third + // value should be correct, and it should always be within one count of + // either the first or the second value. + // + // Just in case, we'll check against the previous two values to make + // sure that our final answer was reasonable. If it isn't, we will + // flag it as a "bad read", and fail this assert statement. + // + // This shouldn't ever happen, and it hasn't ever happened in any of + // our tests so far. + // + am_hal_debug_assert_msg((adjacent(ui32Values[1], ui32Values[2]) || + adjacent(ui32Values[0], ui32Values[2])), + "Bad CDT read"); + } + + return ui32Value; +} + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.h b/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.h new file mode 100644 index 0000000000..63766fa458 --- /dev/null +++ b/bsp/apollo2/libraries/drivers/hal/am_hal_wdt.h @@ -0,0 +1,184 @@ +//***************************************************************************** +// +// am_hal_wdt.h +//! @file +//! +//! @brief Hardware abstraction layer for the Watchdog Timer module. +//! +//! @addtogroup wdt2 Watchdog Timer (WDT) +//! @ingroup apollo2hal +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Copyright (c) 2017, Ambiq Micro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// This is part of revision 1.2.9 of the AmbiqSuite Development Package. +// +//***************************************************************************** +#ifndef AM_HAL_WDT_H +#define AM_HAL_WDT_H + +#include +#include + +//***************************************************************************** +// +// Macro definitions +// +//***************************************************************************** + +//***************************************************************************** +// +//! @name WDT Clock Divider Selections. +//! @brief Macro definitions for WDT clock frequencies. +//! +//! These macros may be used with the am_hal_wdt_config_t structure to set the +//! clock frequency of the watch dog timer. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_WDT_LFRC_CLK_DEFAULT AM_REG_WDT_CFG_CLKSEL_128HZ +#define AM_HAL_WDT_LFRC_CLK_128HZ AM_REG_WDT_CFG_CLKSEL_128HZ +#define AM_HAL_WDT_LFRC_CLK_16HZ AM_REG_WDT_CFG_CLKSEL_16HZ +#define AM_HAL_WDT_LFRC_CLK_1HZ AM_REG_WDT_CFG_CLKSEL_1HZ +#define AM_HAL_WDT_LFRC_CLK_1_16HZ AM_REG_WDT_CFG_CLKSEL_1_16HZ +#define AM_HAL_WDT_LFRC_CLK_OFF AM_REG_WDT_CFG_CLKSEL_OFF +//! @} + +//***************************************************************************** +// +//! @name WDT Enable Reset in the WDT Configuration. +//! @brief Macro definitions for WDT Reset Enable. +//! +//! These macros may be used with the am_hal_wdt_config_t structure to enable +//! the watch dog timer to generate resets to the chip. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_WDT_ENABLE_RESET AM_REG_WDT_CFG_RESEN(1) +#define AM_HAL_WDT_DISABLE_RESET AM_REG_WDT_CFG_RESEN(0) +//! @} + +//***************************************************************************** +// +//! @name WDT Enable Interrupt Generation from the WDT Configuration. +//! @brief Macro definitions for WDT Interrupt Enable. +//! +//! These macros may be used with the am_hal_wdt_config_t structure to enable +//! the watch dog timer to generate generate WDT interrupts. +//! +//! @{ +// +//***************************************************************************** +#define AM_HAL_WDT_ENABLE_INTERRUPT AM_REG_WDT_CFG_INTEN(1) +#define AM_HAL_WDT_DISABLE_INTERRUPT AM_REG_WDT_CFG_INTEN(0) +//! @} + +//***************************************************************************** +// +//! @brief Watchdog timer configuration structure. +//! +//! This structure is made to be used with the am_hal_wdt_init() function. It +//! describes the configuration of the watchdog timer. +// +//***************************************************************************** +typedef struct +{ + //! Configuration Values for watchdog timer + //! event is generated. + uint32_t ui32Config; + + //! Number of watchdog timer ticks allowed before a watchdog interrupt + //! event is generated. + uint16_t ui16InterruptCount; + + //! Number of watchdog timer ticks allowed before the watchdog will issue a + //! system reset. + uint16_t ui16ResetCount; + +} +am_hal_wdt_config_t; + + +//***************************************************************************** +// +//! @brief Restarts the watchdog timer ("Pets" the dog) +//! +//! This function restarts the watchdog timer from the beginning, preventing +//! any interrupt or reset even from occuring until the next time the watchdog +//! timer expires. +//! +//! @return None. +// +//***************************************************************************** +#define am_hal_wdt_restart() \ + do \ + { \ + AM_REGn(WDT, 0, RSTRT) = AM_REG_WDT_RSTRT_RSTRT_KEYVALUE; \ + (void)AM_REGn(WDT, 0, RSTRT); \ + } \ + while(0) + +#ifdef __cplusplus +extern "C" +{ +#endif +//***************************************************************************** +// +// External function definitions +// +//***************************************************************************** +extern void am_hal_wdt_init(const am_hal_wdt_config_t *psConfig); +extern void am_hal_wdt_start(void); +extern void am_hal_wdt_halt(void); +extern void am_hal_wdt_lock_and_start(void); +extern void am_hal_wdt_int_enable(void); +extern uint32_t am_hal_wdt_int_enable_get(void); +extern void am_hal_wdt_int_disable(void); +extern void am_hal_wdt_int_clear(void); +extern void am_hal_wdt_int_set(void); +extern uint32_t am_hal_wdt_int_status_get(bool bEnabledOnly); +#ifdef __cplusplus +} +#endif + +#endif // AM_HAL_WDT_H + +//***************************************************************************** +// +// End Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1