//***************************************************************************** // // am_hal_gpio.c //! @file //! //! @brief Functions for interfacing with the GPIO module //! //! @addtogroup gpio3 GPIO //! @ingroup apollo3hal //! @{ // //***************************************************************************** //***************************************************************************** // // Copyright (c) 2020, 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. // // Third party software included in this distribution is subject to the // additional license terms as defined in the /docs/licenses directory. // // 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 2.4.2 of the AmbiqSuite Development Package. // //***************************************************************************** #include #include #include "am_mcu_apollo.h" //***************************************************************************** // Local defines. //***************************************************************************** // // Generally define GPIO PADREG and GPIOCFG bitfields // // PADREG registers #define PADREG_FLD_76_S 6 #define PADREG_FLD_FNSEL_S 3 #define PADREG_FLD_DRVSTR_S 2 #define PADREG_FLD_INPEN_S 1 #define PADREG_FLD_PULLUP_S 0 #define PADREG_FLD_76_Msk 0xA0 #define PADREG_FLD_FNSEL_Msk 0x38 #define PADREG_FLD_DRVSTR_Msk 0x04 #define PADREG_FLD_INPEN_Msk 0x02 #define PADREG_FLD_PULLUP_Msk 0x01 // ALTPADCFG registers #define ALTPADCFG_FLD_DRVSTR1_S 0 #define ALTPADCFG_FLD_DRVSTR1_Msk 0x01 // CFG registers #define GPIOCFG_FLD_INTD_S 3 #define GPIOCFG_FLD_OUTCFG_S 1 #define GPIOCFG_FLD_INCFG_S 0 #define GPIOCFG_FLD_INTD_Msk 0x08 #define GPIOCFG_FLD_OUTCFG_Msk 0x06 #define GPIOCFG_FLD_INCFG_Msk 0x01 //***************************************************************************** // // Globals // //***************************************************************************** //***************************************************************************** // Define some common GPIO configurations. //***************************************************************************** const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_DISABLE = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_TRISTATE = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_TRISTATE }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN }; // // Input with various pullups (weak, 1.5K, 6K, 12K, 24K) // The 1.5K - 24K pullup values are valid for select I2C enabled pads. // For Apollo3 these pins are 0-1,5-6,8-9,25,27,39-40,42-43,48-49. // The "weak" value is used for almost every other pad except pin 20. // const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN, .ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_1_5 = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN, .ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_6 = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN, .ePullup = AM_HAL_GPIO_PIN_PULLUP_6K }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_12 = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN, .ePullup = AM_HAL_GPIO_PIN_PULLUP_12K }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_24 = { .uFuncSel = 3, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN, .ePullup = AM_HAL_GPIO_PIN_PULLUP_24K }; // // Variations of output (drive strengths, read, etc) // const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_4 = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_4MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_8 = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_12 = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL }; const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_WITH_READ = { .uFuncSel = 3, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA, .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL, .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN }; //***************************************************************************** // // g_ui8Inpen[] // This lookup table determines whether the INPEN bit is required based on // the pin number and FNSEL. // //***************************************************************************** static const uint8_t g_ui8Inpen[AM_HAL_GPIO_MAX_PADS] = { //0 1 2 3 4 5 6 7 8 9 0x23, 0x23, 0x27, 0x62, 0xA1, 0x03, 0x87, 0x10, 0x03, 0x53, // Pins 0-9 0x00, 0xE1, 0x51, 0x81, 0x41, 0x55, 0x05, 0xC4, 0x80, 0x40, // Pins 10-19 0x01, 0xB1, 0x40, 0x41, 0x14, 0x31, 0xA0, 0x31, 0x00, 0xF1, // Pins 20-29 0x80, 0x11, 0x91, 0x21, 0xC1, 0x11, 0xE5, 0x11, 0x45, 0x30, // Pins 30-39 0x37, 0x00, 0x30, 0x31, 0x00, 0x71, 0x00, 0x40, 0x30, 0x31 // Pins 40-49 }; //***************************************************************************** // // g_ui8Bit76Capabilities[] // This lookup table specifies capabilities of each pad for PADREG bits 7:6. // //***************************************************************************** #define CAP_PUP 0x01 // PULLUP #define CAP_PDN 0x08 // PULLDOWN (pin 20 only) #define CAP_VDD 0x02 // VDD PWR (power source) #define CAP_VSS 0x04 // VSS PWR (ground sink) #define CAP_RSV 0x80 // bits 7:6 are reserved for this pin static const uint8_t g_ui8Bit76Capabilities[AM_HAL_GPIO_MAX_PADS] = { //0 1 2 3 4 5 6 7 8 9 CAP_PUP, CAP_PUP, CAP_RSV, CAP_VDD, CAP_RSV, CAP_PUP, CAP_PUP, CAP_RSV, CAP_PUP, CAP_PUP, // Pins 0-9 CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, // Pins 10-19 CAP_PDN, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_PUP, CAP_RSV, CAP_PUP, CAP_RSV, CAP_RSV, // Pins 20-29 CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_VDD, CAP_VSS, CAP_RSV, CAP_PUP, // Pins 30-39 CAP_PUP, CAP_VSS, CAP_PUP, CAP_PUP, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_PUP, CAP_PUP // Pins 40-49 }; //***************************************************************************** // // g_ui8nCEpins[] // This lookup table lists the nCE funcsel value as a function of the pin. // Almost every pad has a nCE function (except for 4 pads). Every one of those // nCE functions can select a polarity (active low or high) via the INTD field. // All non-nCE functions use INCFG and INTD to select interrupt transition types. // A lookup will return 0-7 if the pin supports nCE, and 8 if it does not. // // The truth table summarizes behavior. For the purposes of this table, assume // "A" is the funcsel that selects nCE (and thus polarity is needed) for the // given pad. Then "!A" is any other funcsel and selects interrupt transition. // // funcsel INCFG INTD Behavior // !A 0 0 Interrupt on L->H transition. // !A 0 1 Interrupt on H->L transition. // !A 1 0 No interrupts. // !A 1 1 Interrupt either direction. // A x 0 nCE polarity active low. // A x 1 nCE polarity active high. // //***************************************************************************** static const uint8_t g_ui8nCEpins[AM_HAL_GPIO_MAX_PADS] = { // 0 1 2 3 4 5 6 7 8 9 0x07, 0x07, 0x07, 0x02, 0x02, 0x08, 0x08, 0x00, 0x02, 0x02, // Pads 0-9 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // Pads 10-19 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // Pads 20-29 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, // Pads 30-39 0x08, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 // Pads 40-49 }; //***************************************************************************** // // g_ui8NCEtable[] // This lookup table lists all available NCEs. It basically reproduces the // "NCE Encoding Table" from the datasheet. // The format of this table is: // High nibble=IOM number; 0-5, MSPI=6 (IOMNUM_MSPI). // Low nibble=CE number (0-3). // Every 4 bytes (word) represent the next GPIO number/index. // //***************************************************************************** static const uint8_t g_ui8NCEtable[AM_HAL_GPIO_MAX_PADS][4] = { // 0 1 2 3 = OUTCFG {0x32, 0x42, 0x52, 0x13}, // NCE0 {0x02, 0x12, 0x22, 0x60}, // NCE1 {0x33, 0x43, 0x53, 0x21}, // NCE2 {0x30, 0x40, 0x50, 0x20}, // NCE3 {0x31, 0x41, 0x51, 0x11}, // NCE4 {0xFF, 0xFF, 0xFF, 0xFF}, // NCE5 {0xFF, 0xFF, 0xFF, 0xFF}, // NCE6 {0x31, 0x41, 0x51, 0x60}, // NCE7 {0x30, 0x40, 0x50, 0x00}, // NCE8 {0x33, 0x43, 0x53, 0x23}, // NCE9 {0x32, 0x42, 0x52, 0x60}, // NCE10 {0x00, 0x10, 0x20, 0x30}, // NCE11 {0x30, 0x40, 0x50, 0x61}, // NCE12 {0x31, 0x41, 0x51, 0x01}, // NCE13 {0x02, 0x12, 0x22, 0x42}, // NCE14 {0x03, 0x13, 0x23, 0x60}, // NCE15 {0x00, 0x10, 0x20, 0x50}, // NCE16 {0x01, 0x11, 0x21, 0x41}, // NCE17 {0x02, 0x12, 0x22, 0x32}, // NCE18 {0x03, 0x13, 0x33, 0x60}, // NCE19 {0x31, 0x41, 0x51, 0x21}, // NCE20 {0x32, 0x42, 0x52, 0x22}, // NCE21 {0x33, 0x43, 0x53, 0x03}, // NCE22 {0x00, 0x10, 0x20, 0x40}, // NCE23 {0x01, 0x11, 0x21, 0x51}, // NCE24 {0x32, 0x42, 0x52, 0x02}, // NCE25 {0x33, 0x43, 0x53, 0x13}, // NCE26 {0x30, 0x40, 0x50, 0x10}, // NCE27 {0x31, 0x41, 0x51, 0x60}, // NCE28 {0x32, 0x42, 0x52, 0x12}, // NCE29 {0x33, 0x43, 0x53, 0x03}, // NCE30 {0x00, 0x10, 0x20, 0x40}, // NCE31 {0x01, 0x11, 0x21, 0x61}, // NCE32 {0x02, 0x12, 0x22, 0x52}, // NCE33 {0x03, 0x13, 0x23, 0x33}, // NCE34 {0x00, 0x10, 0x20, 0x30}, // NCE35 {0x31, 0x41, 0x51, 0x61}, // NCE36 {0x32, 0x42, 0x52, 0x02}, // NCE37 {0x03, 0x13, 0x33, 0x53}, // NCE38 {0xFF, 0xFF, 0xFF, 0xFF}, // NCE39 {0xFF, 0xFF, 0xFF, 0xFF}, // NCE40 {0x01, 0x11, 0x21, 0x61}, // NCE41 {0x00, 0x10, 0x20, 0x50}, // NCE42 {0x01, 0x11, 0x21, 0x61}, // NCE43 {0x02, 0x12, 0x22, 0x52}, // NCE44 {0x33, 0x43, 0x53, 0x13}, // NCE45 {0x30, 0x40, 0x50, 0x61}, // NCE46 {0x01, 0x11, 0x21, 0x31}, // NCE47 {0x02, 0x12, 0x22, 0x32}, // NCE48 {0x03, 0x13, 0x23, 0x43} // NCE49 }; // declare ap3_gpio_get_pinconfig_bitmasks void ap3_gpio_get_pinconfig_bitmasks(am_hal_gpio_pincfg_allow_t sAllowableChanges, uint8_t *padRegMask, uint8_t *GPCfgMask, uint8_t *altPadCfgMask); //***************************************************************************** // // Array of function pointers for handling GPIO interrupts. // //***************************************************************************** static am_hal_gpio_handler_t gpio_ppfnHandlers[AM_HAL_GPIO_MAX_PADS]; static void *gpio_pHandlerCtxt[AM_HAL_GPIO_MAX_PADS]; //***************************************************************************** // // Helper functions // popcount() - Determine how many bits are set in the given bitmasks. // pincfg_equ() - compare 2 am_hal_gpio_pincfg_t structures for equality. // //***************************************************************************** static bool pincfg_equ(void *cfg1, void *cfg2) { uint32_t ui32A, ui32B; // // We're assuming that am_hal_gpio_pincfg_t boils down to a uint32_t, // which is its intent. // ui32A = *((uint32_t*)cfg1); ui32B = *((uint32_t*)cfg2); return ui32A == ui32B ? true : false; } // pincfg_equ() static uint32_t popcount(uint64_t ui64bitmask) { uint32_t uCnt = 0; while ( ui64bitmask ) { uCnt += ui64bitmask & 1; ui64bitmask >>= 1; } return uCnt; } // popcount() //***************************************************************************** // //! @brief Configure an Apollo3 pin. //! //! @param ui32Pin - pin number to be configured. //! @param ui32Config - Contains multiple descriptor fields. //! //! This function configures a pin according to the parameters in ui32Config. //! All parameters are validated, and the given pin is configured according //! to the designated parameters. //! //! @return Status. // //***************************************************************************** uint32_t am_hal_gpio_pinconfig(uint32_t ui32Pin, am_hal_gpio_pincfg_t bfGpioCfg) { uint32_t ui32Padreg, ui32AltPadCfg, ui32GPCfg; uint32_t ui32Funcsel, ui32PowerSw; bool bClearEnable = false; #ifndef AM_HAL_DISABLE_API_VALIDATION if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Initialize the PADREG accumulator variables. // ui32GPCfg = ui32Padreg = ui32AltPadCfg = 0; // // Get the requested function and/or power switch. // ui32Funcsel = bfGpioCfg.uFuncSel; ui32PowerSw = bfGpioCfg.ePowerSw; ui32Padreg |= ui32Funcsel << PADREG_FLD_FNSEL_S; // // Check for invalid configuration requests. // if ( bfGpioCfg.ePullup != AM_HAL_GPIO_PIN_PULLUP_NONE ) { // // This setting is needed for all pullup settings including // AM_HAL_GPIO_PIN_PULLUP_WEAK and AM_HAL_GPIO_PIN_PULLDOWN. // ui32Padreg |= (0x1 << PADREG_FLD_PULLUP_S); // // Check for specific pullup or pulldown settings. // if ( (bfGpioCfg.ePullup >= AM_HAL_GPIO_PIN_PULLUP_1_5K) && (bfGpioCfg.ePullup <= AM_HAL_GPIO_PIN_PULLUP_24K) ) { ui32Padreg |= ((bfGpioCfg.ePullup - AM_HAL_GPIO_PIN_PULLUP_1_5K) << PADREG_FLD_76_S); #ifndef AM_HAL_DISABLE_API_VALIDATION if ( !(g_ui8Bit76Capabilities[ui32Pin] & CAP_PUP) ) { return AM_HAL_GPIO_ERR_PULLUP; } } else if ( bfGpioCfg.ePullup == AM_HAL_GPIO_PIN_PULLDOWN ) { if ( ui32Pin != 20 ) { return AM_HAL_GPIO_ERR_PULLDOWN; } } else if ( bfGpioCfg.ePullup == AM_HAL_GPIO_PIN_PULLUP_WEAK ) { // // All pads except 20 support a weak pullup, for which we only need // to set PADnPULL and clear 7:6 (already done at this point). // if ( ui32Pin == 20 ) { return AM_HAL_GPIO_ERR_PULLUP; } #endif // AM_HAL_DISABLE_API_VALIDATION } } // // Check if requesting a power switch pin // if ( ui32PowerSw != AM_HAL_GPIO_PIN_POWERSW_NONE ) { if ( (ui32PowerSw == AM_HAL_GPIO_PIN_POWERSW_VDD) && (g_ui8Bit76Capabilities[ui32Pin] & CAP_VDD) ) { ui32Padreg |= 0x1 << PADREG_FLD_76_S; } else if ( (ui32PowerSw == AM_HAL_GPIO_PIN_POWERSW_VSS) && (g_ui8Bit76Capabilities[ui32Pin] & CAP_VSS) ) { ui32Padreg |= 0x2 << PADREG_FLD_76_S; } else { return AM_HAL_GPIO_ERR_PWRSW; } } // // Depending on the selected pin and FNSEL, determine if INPEN needs to be set. // ui32Padreg |= (g_ui8Inpen[ui32Pin] & (1 << ui32Funcsel)) ? (1 << PADREG_FLD_INPEN_S) : 0; // // Configure ui32GpCfg based on whether nCE requested. // if ( g_ui8nCEpins[ui32Pin] == ui32Funcsel ) { uint32_t ui32Outcfg; uint8_t ui8CEtbl; #ifndef AM_HAL_DISABLE_API_VALIDATION // // User is configuring a nCE. Verify the requested settings and set the // polarity and OUTCFG values (INCFG is not used here and should be 0). // Valid uNCE values are 0-3 (uNCE is a 2-bit field). // Valid uIOMnum are 0-6 (0-5 for IOMs, 6 for MSPI, 7 is invalid). // if ( bfGpioCfg.uIOMnum > IOMNUM_MAX ) { return AM_HAL_GPIO_ERR_INVCE; // Invalid CE specified } #endif // AM_HAL_DISABLE_API_VALIDATION // // Construct the entry we expect to find in the table. We can determine // the OUTCFG value by looking for that value in the pin row. // ui8CEtbl = (bfGpioCfg.uIOMnum << 4) | bfGpioCfg.uNCE; for ( ui32Outcfg = 0; ui32Outcfg < 4; ui32Outcfg++ ) { if ( g_ui8NCEtable[ui32Pin][ui32Outcfg] == ui8CEtbl ) { break; } } #ifndef AM_HAL_DISABLE_API_VALIDATION if ( ui32Outcfg >= 4 ) { return AM_HAL_GPIO_ERR_INVCEPIN; } #endif // AM_HAL_DISABLE_API_VALIDATION ui32GPCfg |= (ui32Outcfg << GPIOCFG_FLD_OUTCFG_S) | (bfGpioCfg.eCEpol << GPIOCFG_FLD_INTD_S) | (0 << GPIOCFG_FLD_INCFG_S); } else { // // It's not nCE, it's one of the other funcsels. // Start by setting the value of the requested GPIO input. // ui32Padreg |= (bfGpioCfg.eGPInput << PADREG_FLD_INPEN_S); // // Map the requested interrupt direction settings into the Apollo3 // GPIOCFG register field, which is a 4-bit field: // [INTD(1):OUTCFG(2):INCFG(1)]. // Bit0 of eIntDir maps to GPIOCFG.INTD (b3). // Bit1 of eIntDir maps to GPIOCFG.INCFG (b0). // ui32GPCfg |= (bfGpioCfg.eGPOutcfg << GPIOCFG_FLD_OUTCFG_S) | (((bfGpioCfg.eIntDir >> 0) & 0x1) << GPIOCFG_FLD_INTD_S) | (((bfGpioCfg.eIntDir >> 1) & 0x1) << GPIOCFG_FLD_INCFG_S); if ( (bfGpioCfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) || pincfg_equ(&bfGpioCfg, (void*)&g_AM_HAL_GPIO_DISABLE) ) { // // For pushpull configurations, we must be sure to clear the ENABLE // bit. In pushpull, these bits turn on FAST GPIO. For regular // GPIO, they must be clear. // bClearEnable = true; } // // There is some overlap between eGPRdZero and eIntDir as both settings // utilize the overloaded INCFG bit. // Therefore the two fields should be used in a mutually exclusive // manner. For flexibility however they are not disallowed because // their functionality is dependent on FUNCSEL and whether interrupts // are used. // // In the vein of mutual exclusion, eGPRdZero is primarily intended for // use when GPIO interrupts are not in use and can be used when no // eIntDir setting is provided. // If eIntDir is provided, eGPRdZero is ignored and can only be // achieved via the AM_HAL_GPIO_PIN_INTDIR_NONE setting. // if ( bfGpioCfg.eIntDir == 0 ) { ui32GPCfg &= ~(1 << GPIOCFG_FLD_INCFG_S); ui32GPCfg |= (bfGpioCfg.eGPRdZero << GPIOCFG_FLD_INCFG_S); } } switch ( bfGpioCfg.eDriveStrength ) { // DRIVESTRENGTH is a 2-bit field. // bit0 maps to bit2 of a PADREG field. // bit1 maps to bit0 of an ALTPADCFG field. case AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA: ui32Padreg |= (0 << PADREG_FLD_DRVSTR_S); ui32AltPadCfg |= (0 << 0); break; case AM_HAL_GPIO_PIN_DRIVESTRENGTH_4MA: ui32Padreg |= (1 << PADREG_FLD_DRVSTR_S); ui32AltPadCfg |= (0 << 0); break; case AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA: ui32Padreg |= (0 << PADREG_FLD_DRVSTR_S); ui32AltPadCfg |= (1 << 0); break; case AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA: ui32Padreg |= (1 << PADREG_FLD_DRVSTR_S); ui32AltPadCfg |= (1 << 0); break; } // // At this point, the 3 configuration variables, ui32GPCfg, ui32Padreg, // and ui32AltPadCfg values are set (at bit position 0) and ready to write // to their respective register bitfields. // uint32_t ui32GPCfgAddr, ui32PadregAddr, ui32AltpadAddr; uint32_t ui32GPCfgClearMask, ui32PadClearMask; uint32_t ui32GPCfgShft, ui32PadShft; ui32GPCfgAddr = AM_REGADDR(GPIO, CFGA) + ((ui32Pin >> 1) & ~0x3); ui32PadregAddr = AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3); ui32AltpadAddr = AM_REGADDR(GPIO, ALTPADCFGA) + (ui32Pin & ~0x3); ui32GPCfgShft = ((ui32Pin & 0x7) << 2); ui32PadShft = ((ui32Pin & 0x3) << 3); ui32GPCfgClearMask = ~((uint32_t)0xF << ui32GPCfgShft); ui32PadClearMask = ~((uint32_t)0xFF << ui32PadShft); // // Get the new values into their rightful bit positions. // ui32Padreg <<= ui32PadShft; ui32AltPadCfg <<= ui32PadShft; ui32GPCfg <<= ui32GPCfgShft; AM_CRITICAL_BEGIN if ( bClearEnable ) { // // We're configuring a mode that requires clearing the Enable bit. // am_hal_gpio_output_tristate_disable(ui32Pin); } GPIO->PADKEY = GPIO_PADKEY_PADKEY_Key; AM_REGVAL(ui32PadregAddr) = (AM_REGVAL(ui32PadregAddr) & ui32PadClearMask) | ui32Padreg; AM_REGVAL(ui32GPCfgAddr) = (AM_REGVAL(ui32GPCfgAddr) & ui32GPCfgClearMask) | ui32GPCfg; AM_REGVAL(ui32AltpadAddr) = (AM_REGVAL(ui32AltpadAddr) & ui32PadClearMask) | ui32AltPadCfg; GPIO->PADKEY = 0; AM_CRITICAL_END return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_pinconfig() //***************************************************************************** // // brief Configure specified pins for FAST GPIO operation. // // ui64PinMask - a mask specifying up to 8 pins to be configured and // used for FAST GPIO (only bits 0-49 are valid). // bfGpioCfg - The GPIO configuration (same as am_hal_gpio_pinconfig()). // All of the pins specified by ui64PinMask will be set to this // configuration. // ui32Masks - If provided, an array to receive 2 32-bit values of the // SET and CLEAR masks that are used for the BBSETCLEAR reg. // Two 32-bit wds are placed for each pin indicated by the mask. // The 2 32-bit values will be placed at incremental indexes. // For example, say pin numbers 5 and 19 are indicated in the // mask, and an array pointer is provided in ui32Masks. This // array must be allocated by the caller to be at least 4 words. // ui32Masks[0] = the set mask used for pin 5. // ui32Masks[1] = the clear mask used for pin 5. // ui32Masks[2] = the set mask used for pin 19. // ui32Masks[3] = the clear mask used for pin 19. // It is recommended that this array be allocated to 16 uint32_t. // //***************************************************************************** uint32_t am_hal_gpio_fast_pinconfig(uint64_t ui64PinMask, am_hal_gpio_pincfg_t bfGpioCfg, uint32_t ui32Masks[]) { uint32_t ux, ui32pinnum, ui32retval, ui32Mask; #ifndef AM_HAL_DISABLE_API_VALIDATION if ( (ui64PinMask & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1)) || (popcount(ui64PinMask) > 8) || (bfGpioCfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_TRISTATE) ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Roll through the pin mask and configure any designated pins per the // bfGpioCfg parameter, and enable for Fast GPIO. // ui32Mask = 0; ui32pinnum = 0; ux = 0; while ( ui64PinMask ) { if ( ui64PinMask & 0x1 ) { // // It is assumed that the caller will have disabled Fast GPIO and // initialized the pin value before calling this function. Therefore // no value initialization is done before the pin configuration, nor // is the am_hal_gpio_fastgpio_disable() called here. // // Configure the pin. // ui32retval = am_hal_gpio_pinconfig(ui32pinnum, bfGpioCfg); if ( ui32retval ) { return ui32retval; } ui32Mask |= 1 << (ui32pinnum & 0x7); // // Enable the FAST GPIO for this pin // am_hal_gpio_fastgpio_enable(ui32pinnum); if ( ui32Masks ) { ui32Masks[ux + 0] = _VAL2FLD(APBDMA_BBSETCLEAR_SET, ui32Mask); ui32Masks[ux + 1] = _VAL2FLD(APBDMA_BBSETCLEAR_CLEAR, ui32Mask); } ux += 2; // Get next indexes } ui32pinnum++; ui64PinMask >>= 1; } return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_fast_pinconfig() //***************************************************************************** // //! @brief Read GPIO. //! //! @param ui32Pin - pin number to be read. //! @param eReadType - State type to read. One of: //! AM_HAL_GPIO_INPUT_READ //! AM_HAL_GPIO_OUTPUT_READ //! AM_HAL_GPIO_ENABLE_READ //! @param pui32ReadState - Pointer to the value to contain the read state. //! When reading the value of a bit, will be either 0 or 1. //! //! This function reads a pin state as given by ui32Type. //! //! @return Status. // //***************************************************************************** uint32_t am_hal_gpio_state_read(uint32_t ui32Pin, am_hal_gpio_read_type_e eReadType, uint32_t *pui32ReadState) { uint32_t ui32ReadValue = 0xFFFFFFFF; uint32_t ui32BaseAddr, ui32Shift; #ifndef AM_HAL_DISABLE_API_VALIDATION if ( pui32ReadState == NULL ) { return AM_HAL_STATUS_INVALID_ARG; } if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS ) { *pui32ReadState = ui32ReadValue; return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Compute base address + offset of 0 or 4. // ui32BaseAddr = ((ui32Pin & 0x20) >> 3); // 0 or 4 ui32Shift = ui32Pin & 0x1F; switch ( eReadType ) { case AM_HAL_GPIO_INPUT_READ: // // Assumes eIntDir != AM_HAL_GPIO_PIN_INTDIR_NONE && // eIntDir != AM_HAL_GPIO_PIN_INTDIR_BOTH // If either of those configs are set, returns 0. // ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, RDA) + ui32BaseAddr); ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01; break; case AM_HAL_GPIO_OUTPUT_READ: ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, WTA) + ui32BaseAddr); ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01; break; case AM_HAL_GPIO_ENABLE_READ: ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, ENA) + ui32BaseAddr); ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01; break; default: return AM_HAL_STATUS_INVALID_ARG; } *pui32ReadState = ui32ReadValue; return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_state_read() //***************************************************************************** // //! @brief Write GPIO. //! //! @param ui32Pin - pin number to be read. //! //! @param ui32Type - State type to write. One of: //! AM_HAL_GPIO_OUTPUT_SET - Write a one to a GPIO. //! AM_HAL_GPIO_OUTPUT_CLEAR - Write a zero to a GPIO. //! AM_HAL_GPIO_OUTPUT_TOGGLE - Toggle the GPIO value. //! The following two apply when output is set for TriState (OUTCFG==3). //! AM_HAL_GPIO_OUTPUT_TRISTATE_ENABLE - Enable a tri-state GPIO. //! AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE - Disable a tri-state GPIO. //! //! This function writes a GPIO value. //! //! @return Status. //! Fails if the pad is not configured for GPIO (PADFNCSEL != 3). // //***************************************************************************** uint32_t am_hal_gpio_state_write(uint32_t ui32Pin, am_hal_gpio_write_type_e eWriteType) { uint32_t ui32Mask, ui32Off; uint32_t ui32Return = AM_HAL_STATUS_SUCCESS; #ifndef AM_HAL_DISABLE_API_VALIDATION if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS ) { return AM_HAL_STATUS_OUT_OF_RANGE; } if ( eWriteType > AM_HAL_GPIO_OUTPUT_TRISTATE_TOGGLE ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION ui32Mask = (uint32_t)0x1 << (ui32Pin % 32); ui32Off = (ui32Pin & 0x20) >> 3; // 0 or 4 AM_CRITICAL_BEGIN; switch ( eWriteType ) { case AM_HAL_GPIO_OUTPUT_SET: // Write a one to a GPIO. AM_REGVAL(AM_REGADDR(GPIO, WTSA) + ui32Off) = ui32Mask; break; case AM_HAL_GPIO_OUTPUT_CLEAR: // Write a zero to a GPIO. AM_REGVAL(AM_REGADDR(GPIO, WTCA) + ui32Off) = ui32Mask; break; case AM_HAL_GPIO_OUTPUT_TOGGLE: // Toggle the GPIO value. AM_REGVAL(AM_REGADDR(GPIO, WTA) + ui32Off) ^= ui32Mask; break; case AM_HAL_GPIO_OUTPUT_TRISTATE_ENABLE: // Enable a tri-state GPIO. AM_REGVAL(AM_REGADDR(GPIO, ENSA) + ui32Off) = ui32Mask; break; case AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE: // Disable a tri-state GPIO. AM_REGVAL(AM_REGADDR(GPIO, ENCA) + ui32Off) = ui32Mask; break; case AM_HAL_GPIO_OUTPUT_TRISTATE_TOGGLE: // Toggle a tri-state GPIO. AM_REGVAL(AM_REGADDR(GPIO, ENCA) + ui32Off) ^= ui32Mask; break; default: // Type values were validated on entry. // We can't return from here because we're in a critical section. ui32Return = AM_HAL_STATUS_INVALID_ARG; break; } AM_CRITICAL_END; return ui32Return; } // am_hal_gpio_state_write() //***************************************************************************** // // Enable GPIO interrupts. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_enable(uint64_t ui64InterruptMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui64InterruptMask & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Enable the interrupts. // AM_CRITICAL_BEGIN GPIO->INT0EN |= (uint32_t)(ui64InterruptMask & 0xFFFFFFFF); GPIO->INT1EN |= (uint32_t)(ui64InterruptMask >> 32); AM_CRITICAL_END // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_enable() //***************************************************************************** // // Disable GPIO interrupts. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_disable(uint64_t ui64InterruptMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui64InterruptMask & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Disable the interrupts. // AM_CRITICAL_BEGIN GPIO->INT0EN &= ~((uint32_t)(ui64InterruptMask & 0xFFFFFFFF)); GPIO->INT1EN &= ~((uint32_t)(ui64InterruptMask >> 32)); AM_CRITICAL_END // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_disable() //***************************************************************************** // // Clear GPIO interrupts. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_clear(uint64_t ui64InterruptMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui64InterruptMask & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Clear the interrupts. // AM_CRITICAL_BEGIN GPIO->INT0CLR = (uint32_t)(ui64InterruptMask & 0xFFFFFFFF); GPIO->INT1CLR = (uint32_t)(ui64InterruptMask >> 32); AM_CRITICAL_END // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_clear() //***************************************************************************** // // Get GPIO interrupt status. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_status_get(bool bEnabledOnly, uint64_t *pui64IntStatus) { uint64_t ui64RetVal, ui64Mask; #ifndef AM_HAL_DISABLE_API_VALIDATION if ( pui64IntStatus == NULL ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Initialize variable outside critical section // ui64Mask = 0xFFFFFFFFFFFFFFFF; // // Combine upper or lower GPIO words into one 64 bit return value. // AM_CRITICAL_BEGIN ui64RetVal = ((uint64_t)GPIO->INT1STAT) << 32; ui64RetVal |= ((uint64_t)GPIO->INT0STAT) << 0; if ( bEnabledOnly ) { ui64Mask = ((uint64_t)GPIO->INT1EN) << 32; ui64Mask |= ((uint64_t)GPIO->INT0EN) << 0; } ui64RetVal &= ui64Mask; *pui64IntStatus = ui64RetVal; AM_CRITICAL_END // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_status_get() //***************************************************************************** // // GPIO interrupt service routine registration. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_register(uint32_t ui32GPIONumber, am_hal_gpio_handler_t pfnHandler) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui32GPIONumber >= AM_HAL_GPIO_MAX_PADS ) { return AM_HAL_STATUS_OUT_OF_RANGE; } if ( pfnHandler == NULL ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Store the handler function pointer. // gpio_ppfnHandlers[ui32GPIONumber] = pfnHandler; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_register() //***************************************************************************** // //! @brief Advanced GPIO interrupt service routine registration. //! //! @param ui32GPIONumber - GPIO number (0-49) to be registered. //! //! @param pfnHandler - Function pointer to the callback. //! //! @param pCtxt - context for the callback. //! //! @return Status. //! Fails if pfnHandler is NULL or ui32GPIONumber > 49. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_register_adv(uint32_t ui32GPIONumber, am_hal_gpio_handler_adv_t pfnHandler, void *pCtxt) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui32GPIONumber >= AM_HAL_GPIO_MAX_PADS ) { return AM_HAL_STATUS_OUT_OF_RANGE; } if ( pfnHandler == NULL ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Store the handler function pointer. // gpio_ppfnHandlers[ui32GPIONumber] = (am_hal_gpio_handler_t)((uint32_t)pfnHandler & ~0x1); gpio_pHandlerCtxt[ui32GPIONumber] = pCtxt; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } // am_hal_gpio_interrupt_register_adv() //***************************************************************************** // // GPIO interrupt service routine. // //***************************************************************************** uint32_t am_hal_gpio_interrupt_service(uint64_t ui64Status) { uint32_t ui32RetStatus = AM_HAL_STATUS_SUCCESS; uint32_t ui32Status, ui32Clz, ui32FFS, ui32Cnt; am_hal_gpio_handler_t pfnHandler; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check parameters // if ( ui64Status & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } if ( ui64Status == 0 ) { return AM_HAL_STATUS_FAIL; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Handle interrupts. // The 1st iteration handles any active interrupts in the lower 32 bits. // The 2nd iteration handles any active interrupts in the upper 32 bits. // (The order of handling upper or lower bits is somewhat arbitrary.) // ui32Cnt = 0; while ( ui32Cnt < 33 ) { // // Get upper or lower status word. // ui32Status = (uint32_t)(ui64Status >> ui32Cnt); while ( ui32Status ) { // // We need to FFS (Find First Set). We can easily zero-base FFS // since we know that at least 1 bit is set in ui32Status. // FFS(x) = 31 - clz(x & -x). // Zero-based version of FFS. // ui32FFS = ui32Status & (uint32_t)(-(int32_t)ui32Status); #ifdef __IAR_SYSTEMS_ICC__ ui32Clz = __CLZ(ui32FFS); #else ui32Clz = __builtin_clz(ui32FFS); #endif ui32FFS = 31 - ui32Clz; // // Turn off the bit we picked in the working copy // ui32Status &= ~(0x00000001 << ui32FFS); // // Check the bit handler table to see if there is an interrupt handler // registered for this particular bit. // pfnHandler = gpio_ppfnHandlers[ui32Cnt + ui32FFS]; if ( pfnHandler ) { // // If we found an interrupt handler routine, call it now. // if ((uint32_t)pfnHandler & 0x1) { pfnHandler(); } else { am_hal_gpio_handler_adv_t padvHandler = (am_hal_gpio_handler_adv_t)((uint32_t)pfnHandler | 0x1); padvHandler(gpio_pHandlerCtxt[ui32Cnt + ui32FFS]); } } else { // // No handler was registered for the GPIO that interrupted. // Return an error. // ui32RetStatus = AM_HAL_STATUS_INVALID_OPERATION; } } ui32Cnt += 32; } // // Return the status. // return ui32RetStatus; } // am_hal_gpio_interrupt_service() //***************************************************************************** // //! @brief //! //! @param ui32Pin - pin number to be configured. //! @param pbfGpioCfg - pointer to am_hal_gpio_pincfg_t structure to fill with current configuration //! //! @return Status. // //***************************************************************************** uint32_t ap3_get_pincfg(uint32_t ui32Pin, am_hal_gpio_pincfg_t* pbfGpioCfg){ // typedef struct // { // uint32_t uFuncSel : 3; // [2:0] Function select (FUNCSEL) // uint32_t ePowerSw : 2; // [4:3] Pin is a power switch source (VCC) or sink (VSS) // uint32_t ePullup : 3; // [7:5] Pin will enable a pullup resistor // uint32_t eDriveStrength : 2; // [9:8] Pad strength designator // uint32_t eGPOutcfg : 2; // [11:10] OUTCFG (GPIO config only) // uint32_t eGPInput : 1; // [12:12] GPIO Input (GPIO config only) // uint32_t eIntDir : 2; // [14:13] Interrupt direction // uint32_t eGPRdZero : 1; // [15:15] GPIO read as zero // // // // The following descriptors designate the chip enable features of the // // pin being configured. If not a CE, these descriptors are ignored. // // uIOMnum is 0-5 for the IOMs, or 6 for MSPI, 7 is invalid. // // // uint32_t uIOMnum : 3; // [18:16] IOM number (0-5), 6 for MSPI // uint32_t uNCE : 2; // [20:19] NCE number (0-3). // uint32_t eCEpol : 1; // [21:21] NCE polarity. // uint32_t uRsvd22 : 10; // [31:22] // } am_hal_gpio_pincfg_t; // helpers uint32_t ui32PadregAddr = AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3); uint32_t ui32AltpadcfgAddr = AM_REGADDR(GPIO, ALTPADCFGA) + (ui32Pin & ~0x3); uint32_t ui32CfgAddr = AM_REGADDR(GPIO, CFGA) + ((ui32Pin >> 1) & ~0x3); uint32_t ui32PadregShft = ((ui32Pin & 0x3) << 3); uint32_t ui32AltpadcfgShft = ((ui32Pin & 0x7) << 2); uint32_t ui32CfgShft = ((ui32Pin & 0x7) << 2); // the pad's register values uint32_t ui32Padreg = (AM_REGVAL(ui32PadregAddr) >> ui32PadregShft); uint32_t ui32Altpadcfg = (AM_REGVAL(ui32AltpadcfgAddr) >> ui32AltpadcfgShft); uint32_t ui32Cfg = (AM_REGVAL(ui32CfgAddr) >> ui32CfgShft); // filling things uint32_t uFuncSel = ((ui32Padreg & PADREG_FLD_FNSEL_Msk) >> PADREG_FLD_FNSEL_S); uint32_t eDriveStrength = ((((ui32Altpadcfg & ALTPADCFG_FLD_DRVSTR1_Msk) >> ALTPADCFG_FLD_DRVSTR1_S) << 1) | ((ui32Padreg & PADREG_FLD_DRVSTR_Msk) >> PADREG_FLD_DRVSTR_S)); uint32_t eGPOutcfg = ((ui32Cfg & GPIOCFG_FLD_OUTCFG_Msk) >> GPIOCFG_FLD_OUTCFG_S ); uint32_t eGPInput = ((ui32Padreg & PADREG_FLD_INPEN_Msk) >> PADREG_FLD_INPEN_S ); uint32_t eIntDir = ((((ui32Cfg & GPIOCFG_FLD_INCFG_Msk) >> GPIOCFG_FLD_INCFG_S) << 1) | ((ui32Cfg & GPIOCFG_FLD_INTD_Msk) >> GPIOCFG_FLD_INTD_S)); // there is interplay between eIntDir and eGPRdZero - this is the best method uint32_t eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN; if(eIntDir == AM_HAL_GPIO_PIN_INTDIR_NONE){ eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_ZERO; } uint32_t ePowerSw = ((ui32Padreg & PADREG_FLD_76_Msk) >> PADREG_FLD_76_S); if(!(g_ui8Bit76Capabilities[ui32Pin] & (CAP_VDD | CAP_VSS))){ ePowerSw = AM_HAL_GPIO_PIN_POWERSW_NONE; } // all pins indicate a pullup using the bit in PADREG_FLD_PULLUP_Msk uint32_t ePullup = ((ui32Padreg & PADREG_FLD_PULLUP_Msk) >> PADREG_FLD_PULLUP_S); if(g_ui8Bit76Capabilities[ui32Pin] & CAP_PUP){ // pins that have addtl. pullup capabilities indicate the config // using the FLD_76 area of the padreg // the configuration of such a pin for 1_5K or WEAK is identical ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; ePullup += ((ui32Padreg & PADREG_FLD_76_Msk) >> PADREG_FLD_76_S); } if(ui32Pin == 20){ if(ePullup){ // pad 20 can't have a pullup, so it must be a pull down ePullup = AM_HAL_GPIO_PIN_PULLDOWN; } } // // note: these settings are not properrly recovered - do not rely on a partial // // pinconfig to retain these settings // uIOMnum // uNCE // eCEpol // pass out pbfGpioCfg->uFuncSel = uFuncSel; pbfGpioCfg->ePowerSw = ePowerSw; pbfGpioCfg->ePullup = ePullup; pbfGpioCfg->eDriveStrength = eDriveStrength; pbfGpioCfg->eGPOutcfg = eGPOutcfg; pbfGpioCfg->eGPInput = eGPInput; pbfGpioCfg->eIntDir = eIntDir; pbfGpioCfg->eGPRdZero = eGPRdZero; // pbfGpioCfg->uIOMnum = uIOMnum; // pbfGpioCfg->uNCE = uNCE; // pbfGpioCfg->eCEpol = eCEpol; return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // //! @brief Configure an Apollo3 pin without overwriting existing settings //! //! @param ui32Pin - pin number to be configured. //! @param ui32Config - Contains multiple descriptor fields. //! @param sAllowableChanges - am_hal_gpio_pincfg_allow_t structure with true elements for fields to change //! //! This function configures a pin according to the parameters in ui32Config. //! All parameters are validated, and the given pin is configured according //! to the designated parameters. //! //! @return Status. // //***************************************************************************** uint32_t ap3_hal_gpio_pinconfig_partial(uint32_t ui32Pin, am_hal_gpio_pincfg_t bfGpioCfg, am_hal_gpio_pincfg_allow_t sAllowableChanges) //am_hal_gpio_pincfg_t bfGpioCfgMsk) { // get current config am_hal_gpio_pincfg_t new_cfg; ap3_get_pincfg(ui32Pin, &new_cfg); // change only requested fields if(sAllowableChanges.uFuncSel) { new_cfg.uFuncSel = bfGpioCfg.uFuncSel; } if(sAllowableChanges.ePowerSw) { new_cfg.ePowerSw = bfGpioCfg.ePowerSw; } if(sAllowableChanges.ePullup) { new_cfg.ePullup = bfGpioCfg.ePullup; } if(sAllowableChanges.eDriveStrength) { new_cfg.eDriveStrength = bfGpioCfg.eDriveStrength; } if(sAllowableChanges.eGPOutcfg) { new_cfg.eGPOutcfg = bfGpioCfg.eGPOutcfg; } if(sAllowableChanges.eGPInput) { new_cfg.eGPInput = bfGpioCfg.eGPInput; } if(sAllowableChanges.eIntDir) { new_cfg.eIntDir = bfGpioCfg.eIntDir; } if(sAllowableChanges.eGPRdZero) { new_cfg.eGPRdZero = bfGpioCfg.eGPRdZero; } if(sAllowableChanges.uIOMnum) { new_cfg.uIOMnum = bfGpioCfg.uIOMnum; } if(sAllowableChanges.uNCE) { new_cfg.uNCE = bfGpioCfg.uNCE; } if(sAllowableChanges.eCEpol) { new_cfg.eCEpol = bfGpioCfg.eCEpol; } // call normal function return am_hal_gpio_pinconfig(ui32Pin, new_cfg); } //***************************************************************************** // // End Doxygen group. //! @} // //*****************************************************************************