1336 lines
48 KiB
C
1336 lines
48 KiB
C
//*****************************************************************************
|
|
//
|
|
// am_hal_gpio.c
|
|
//! @file
|
|
//!
|
|
//! @brief Functions for interfacing with the GPIO module
|
|
//!
|
|
//! @addtogroup gpio3p GPIO
|
|
//! @ingroup apollo3phal
|
|
//! @{
|
|
//
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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 <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "am_mcu_apollo.h"
|
|
|
|
//*****************************************************************************
|
|
// Local defines.
|
|
//*****************************************************************************
|
|
//
|
|
// Generally define GPIO PADREG and GPIOCFG bitfields
|
|
//
|
|
#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 GPIOCFG_FLD_INTD_S 3
|
|
#define GPIOCFG_FLD_OUTCFG_S 1
|
|
#define GPIOCFG_FLD_INCFG_S 0
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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
|
|
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // Pins 50-59
|
|
0x01, 0xA0, 0x50, 0xA0, 0x01, 0x01, 0x01, 0x01, 0x01, 0xA0, // Pins 60-69
|
|
0xA0, 0xA0, 0xA0, 0x50 // Pins 70-73
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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
|
|
CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, // Pins 50-59
|
|
CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, // Pins 60-69
|
|
CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV // Pins 70-73
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// g_ui8nCEpins[]
|
|
// This lookup table lists the nCE funcsel value as a function of the pin.
|
|
// Almost every pad has a nCE function. 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
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // Pads 50-59
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // Pads 60-69
|
|
0x01, 0x01, 0x01, 0x01 // Pads 70-73
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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:
|
|
// [7:7] IOM=1, MSPI=0
|
|
// [6:4] NCE number (0-3)
|
|
// [3:0] IOM number (0-5) or MSPI number (0-2)
|
|
// Every 4 bytes (1 word) of the table represent an index to the next GPIO pin.
|
|
//
|
|
//*****************************************************************************
|
|
//
|
|
// In NCETBL entries, either IOM or MSPI should be 0.
|
|
//
|
|
#define NCETBL(IOM, NUM, NCE) ((IOM << 7) | (NCE << 4) | (NUM << 0))
|
|
|
|
static const uint8_t
|
|
g_ui8NCEtable[AM_HAL_GPIO_MAX_PADS][4] =
|
|
{
|
|
// 0 1 2 3 = OUTCFG
|
|
{NCETBL(1, 3, 2), NCETBL(1, 4, 2), NCETBL(0, 2, 1), NCETBL(0, 1, 0)}, // NCE0
|
|
{NCETBL(1, 0, 2), NCETBL(1, 1, 2), NCETBL(1, 2, 2), NCETBL(1, 4, 2)}, // NCE1
|
|
{NCETBL(1, 3, 3), NCETBL(0, 2, 0), NCETBL(1, 5, 3), NCETBL(1, 2, 1)}, // NCE2
|
|
{NCETBL(1, 3, 0), NCETBL(1, 4, 0), NCETBL(1, 5, 0), NCETBL(1, 2, 0)}, // NCE3
|
|
{NCETBL(1, 3, 1), NCETBL(1, 4, 1), NCETBL(0, 1, 0), NCETBL(1, 1, 1)}, // NCE4
|
|
{0xFF, 0xFF, 0xFF, 0xFF}, // NCE5
|
|
{0xFF, 0xFF, 0xFF, 0xFF}, // NCE6
|
|
{NCETBL(0, 1, 0), NCETBL(0, 2, 1), NCETBL(1, 5, 1), NCETBL(0, 0, 0)}, // NCE7
|
|
{NCETBL(1, 3, 0), NCETBL(1, 4, 0), NCETBL(0, 2, 0), NCETBL(1, 0, 0)}, // NCE8
|
|
{NCETBL(0, 1, 0), NCETBL(1, 4, 3), NCETBL(1, 5, 3), NCETBL(1, 2, 3)}, // NCE9
|
|
{NCETBL(1, 3, 2), NCETBL(1, 4, 2), NCETBL(0, 1, 1), NCETBL(0, 0, 0)}, // NCE10
|
|
{NCETBL(1, 0, 0), NCETBL(1, 1, 0), NCETBL(1, 2, 0), NCETBL(1, 3, 0)}, // NCE11
|
|
{NCETBL(1, 3, 0), NCETBL(0, 2, 0), NCETBL(1, 5, 0), NCETBL(0, 0, 1)}, // NCE12
|
|
{NCETBL(1, 3, 1), NCETBL(1, 4, 1), NCETBL(1, 5, 1), NCETBL(1, 0, 1)}, // NCE13
|
|
{NCETBL(1, 0, 2), NCETBL(0, 2, 1), NCETBL(1, 2, 2), NCETBL(1, 4, 2)}, // NCE14
|
|
{NCETBL(0, 1, 0), NCETBL(1, 1, 3), NCETBL(1, 2, 3), NCETBL(0, 0, 0)}, // NCE15
|
|
{NCETBL(1, 0, 0), NCETBL(0, 2, 0), NCETBL(1, 2, 3), NCETBL(1, 5, 0)}, // NCE16
|
|
{NCETBL(1, 0, 1), NCETBL(1, 1, 1), NCETBL(0, 2, 0), NCETBL(1, 4, 1)}, // NCE17
|
|
{NCETBL(0, 2, 0), NCETBL(1, 1, 2), NCETBL(1, 2, 2), NCETBL(1, 3, 2)}, // NCE18
|
|
{NCETBL(1, 0, 3), NCETBL(0, 1, 1), NCETBL(1, 3, 3), NCETBL(0, 0, 0)}, // NCE19
|
|
{NCETBL(0, 2, 1), NCETBL(0, 0, 0), NCETBL(1, 5, 1), NCETBL(1, 2, 1)}, // NCE20
|
|
{NCETBL(1, 3, 2), NCETBL(1, 4, 2), NCETBL(0, 2, 0), NCETBL(0, 1, 0)}, // NCE21
|
|
{NCETBL(1, 3, 3), NCETBL(1, 4, 3), NCETBL(1, 5, 3), NCETBL(0, 2, 0)}, // NCE22
|
|
{NCETBL(1, 0, 0), NCETBL(1, 1, 0), NCETBL(1, 2, 0), NCETBL(1, 4, 0)}, // NCE23
|
|
{NCETBL(1, 0, 1), NCETBL(0, 1, 0), NCETBL(1, 2, 1), NCETBL(1, 5, 1)}, // NCE24
|
|
{NCETBL(1, 3, 2), NCETBL(0, 1, 0), NCETBL(1, 5, 2), NCETBL(1, 0, 2)}, // NCE25
|
|
{NCETBL(1, 3, 3), NCETBL(1, 4, 3), NCETBL(1, 5, 3), NCETBL(1, 1, 3)}, // NCE26
|
|
{NCETBL(0, 2, 0), NCETBL(1, 4, 0), NCETBL(0, 0, 0), NCETBL(1, 1, 0)}, // NCE27
|
|
{NCETBL(1, 3, 1), NCETBL(1, 4, 1), NCETBL(1, 5, 1), NCETBL(0, 0, 0)}, // NCE28
|
|
{NCETBL(1, 3, 2), NCETBL(0, 2, 1), NCETBL(1, 5, 2), NCETBL(1, 1, 2)}, // NCE29
|
|
{NCETBL(0, 0, 0), NCETBL(1, 4, 3), NCETBL(0, 2, 0), NCETBL(1, 0, 3)}, // NCE30
|
|
{NCETBL(0, 1, 0), NCETBL(0, 2, 0), NCETBL(1, 2, 0), NCETBL(1, 4, 0)}, // NCE31
|
|
{NCETBL(1, 0, 1), NCETBL(1, 1, 3), NCETBL(0, 1, 0), NCETBL(0, 0, 1)}, // NCE32
|
|
{NCETBL(1, 0, 2), NCETBL(0, 1, 1), NCETBL(1, 2, 1), NCETBL(1, 5, 2)}, // NCE33
|
|
{NCETBL(1, 0, 3), NCETBL(0, 2, 0), NCETBL(1, 2, 3), NCETBL(0, 1, 1)}, // NCE34
|
|
{NCETBL(0, 1, 0), NCETBL(1, 1, 0), NCETBL(1, 2, 0), NCETBL(0, 2, 0)}, // NCE35
|
|
{NCETBL(1, 3, 1), NCETBL(1, 4, 1), NCETBL(1, 5, 1), NCETBL(0, 0, 1)}, // NCE36
|
|
{NCETBL(1, 3, 1), NCETBL(1, 4, 2), NCETBL(1, 5, 2), NCETBL(0, 0, 0)}, // NCE37
|
|
{NCETBL(1, 0, 3), NCETBL(1, 1, 3), NCETBL(0, 2, 1), NCETBL(1, 5, 3)}, // NCE38
|
|
{0xFF, 0xFF, 0xFF, 0xFF}, // NCE39
|
|
{0xFF, 0xFF, 0xFF, 0xFF}, // NCE40
|
|
{NCETBL(0,2,0), NCETBL(1,1,1), NCETBL(0,1,1), NCETBL(0,0,1)}, // NCE41
|
|
{NCETBL(1,0,0), NCETBL(0,1,0), NCETBL(1,2,0), NCETBL(1,5,0)}, // NCE42
|
|
{NCETBL(1,0,1), NCETBL(1,1,1), NCETBL(0,2,0), NCETBL(0,0,1)}, // NCE43
|
|
{NCETBL(1,0,2), NCETBL(0,0,0), NCETBL(1,2,2), NCETBL(1,5,2)}, // NCE44
|
|
{NCETBL(1,3,3), NCETBL(1,4,3), NCETBL(1,5,0), NCETBL(1,1,3)}, // NCE45
|
|
{NCETBL(1,3,0), NCETBL(0,1,0), NCETBL(0,2,0), NCETBL(0,0,1)}, // NCE46
|
|
{NCETBL(0,1,1), NCETBL(1,1,0), NCETBL(1,2,1), NCETBL(1,3,1)}, // NCE47
|
|
{NCETBL(0,1,0), NCETBL(1,1,2), NCETBL(1,2,2), NCETBL(0,2,1)}, // NCE48
|
|
{NCETBL(1,0,3), NCETBL(0,1,1), NCETBL(1,2,3), NCETBL(1,1,0)}, // NCE49
|
|
{NCETBL(0,1,0), NCETBL(0,2,0), NCETBL(1,2,3), NCETBL(1,0,0)}, // NCE50
|
|
{NCETBL(1,4,2), NCETBL(1,1,1), NCETBL(1,2,1), NCETBL(1,0,0)}, // NCE51
|
|
{NCETBL(1,0,1), NCETBL(1,1,2), NCETBL(0,0,0), NCETBL(1,2,1)}, // NCE52
|
|
{NCETBL(1,0,2), NCETBL(1,1,3), NCETBL(0,2,0), NCETBL(1,2,0)}, // NCE53
|
|
{NCETBL(0,2,0), NCETBL(1,4,0), NCETBL(1,5,0), NCETBL(1,3,0)}, // NCE54
|
|
{NCETBL(1,3,0), NCETBL(0,0,0), NCETBL(1,5,1), NCETBL(1,4,0)}, // NCE55
|
|
{NCETBL(1,3,2), NCETBL(1,4,3), NCETBL(1,5,2), NCETBL(0,0,1)}, // NCE56
|
|
{NCETBL(0,0,0), NCETBL(1,4,3), NCETBL(1,5,3), NCETBL(1,0,1)}, // NCE57
|
|
{NCETBL(1,3,3), NCETBL(1,1,0), NCETBL(0,0,0), NCETBL(1,5,3)}, // NCE58
|
|
{NCETBL(0,1,1), NCETBL(1,1,1), NCETBL(1,2,1), NCETBL(0,0,0)}, // NCE59
|
|
{NCETBL(0,0,1), NCETBL(1,1,2), NCETBL(1,2,2), NCETBL(1,0,3)}, // NCE60
|
|
{NCETBL(0,0,0), NCETBL(1,1,3), NCETBL(0,2,0), NCETBL(0,1,0)}, // NCE61
|
|
{NCETBL(0,0,1), NCETBL(1,4,0), NCETBL(1,5,0), NCETBL(0,1,1)}, // NCE62
|
|
{NCETBL(0,1,0), NCETBL(1,4,1), NCETBL(0,2,0), NCETBL(0,0,0)}, // NCE63
|
|
{NCETBL(1,0,0), NCETBL(1,4,2), NCETBL(1,5,2), NCETBL(0,0,1)}, // NCE64
|
|
{NCETBL(1,0,1), NCETBL(0,0,0), NCETBL(1,5,2), NCETBL(1,3,1)}, // NCE65
|
|
{NCETBL(0,1,0), NCETBL(1,1,0), NCETBL(1,2,0), NCETBL(1,4,1)}, // NCE66
|
|
{NCETBL(1,0,3), NCETBL(1,1,1), NCETBL(1,2,3), NCETBL(1,5,1)}, // NCE67
|
|
{NCETBL(1,3,0), NCETBL(0,0,0), NCETBL(1,2,2), NCETBL(1,0,2)}, // NCE68
|
|
{NCETBL(1,3,1), NCETBL(1,1,3), NCETBL(0,0,0), NCETBL(0,1,0)}, // NCE69
|
|
{NCETBL(1,3,2), NCETBL(0,2,0), NCETBL(1,5,0), NCETBL(0,1,1)}, // NCE70
|
|
{NCETBL(1,3,3), NCETBL(1,4,1), NCETBL(1,0,3), NCETBL(1,1,2)}, // NCE71
|
|
{NCETBL(0,0,0), NCETBL(0,2,0), NCETBL(0,1,0), NCETBL(1,2,2)}, // NCE72
|
|
{NCETBL(0,1,0), NCETBL(1,4,3), NCETBL(1,5,3), NCETBL(0,2,0)}, // NCE73
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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(uint32_t *pui32bitmask, int32_t i32numbits)
|
|
{
|
|
uint32_t uCnt = 0;
|
|
uint32_t ui32bm;
|
|
|
|
// Count the number of set bits in the given bitmasks.
|
|
uCnt = 0;
|
|
while ( i32numbits > 0 )
|
|
{
|
|
ui32bm = *pui32bitmask++;
|
|
ui32bm &= (((uint32_t)1 << i32numbits) - 1);
|
|
|
|
//
|
|
// This loop will efficiently determine the number of set bits in ui32bm
|
|
//
|
|
while ( ui32bm )
|
|
{
|
|
ui32bm &= (ui32bm - 1);
|
|
uCnt++;
|
|
}
|
|
i32numbits -= 32;
|
|
}
|
|
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;
|
|
|
|
//
|
|
// 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-5 (0-5 for IOMs, 0-2 for MSPI).
|
|
//
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
//
|
|
// Optionally validate the settings.
|
|
//
|
|
if ( bfGpioCfg.uNCE >= 4 )
|
|
{
|
|
return AM_HAL_GPIO_ERR_INVCE; // Invalid CE specified
|
|
}
|
|
|
|
if ( (bfGpioCfg.bIomMSPIn) &&
|
|
(bfGpioCfg.uIOMnum >= AM_REG_IOM_NUM_MODULES) )
|
|
{
|
|
return AM_HAL_GPIO_ERR_INVCE; // Invalid CE specified
|
|
}
|
|
else if ( (!bfGpioCfg.bIomMSPIn) &&
|
|
(bfGpioCfg.uIOMnum >= AM_REG_MSPI_NUM_MODULES) )
|
|
{
|
|
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 = NCETBL(bfGpioCfg.bIomMSPIn, bfGpioCfg.uIOMnum, bfGpioCfg.uNCE);
|
|
|
|
//
|
|
// Now search the NCE table for a match.
|
|
//
|
|
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(am_hal_gpio_mask_t *psPinMask,
|
|
am_hal_gpio_pincfg_t bfGpioCfg,
|
|
uint32_t ui32Masks[])
|
|
{
|
|
uint32_t ux, ui32pinnum, ui32retval, ui32Mask, ui32PinMask;
|
|
uint32_t ui32WdIdx;
|
|
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
if ( psPinMask->U.Msk[AM_HAL_GPIO_NUMWORDS - 1] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS - 64)) - 1) ||
|
|
(popcount((uint32_t*)&psPinMask->U.Msk[0], AM_HAL_GPIO_MAX_PADS) > 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.
|
|
//
|
|
ux = 0;
|
|
ui32pinnum = 0;
|
|
ui32WdIdx = 0;
|
|
while ( ui32pinnum < AM_HAL_GPIO_MAX_PADS )
|
|
{
|
|
ui32PinMask = psPinMask->U.Msk[ui32WdIdx++];
|
|
ui32Mask = 0;
|
|
|
|
while ( ui32PinMask )
|
|
{
|
|
if ( ui32PinMask & 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++;
|
|
ui32PinMask >>= 1;
|
|
}
|
|
ui32pinnum &= ~31;
|
|
ui32pinnum += 32;
|
|
}
|
|
|
|
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 & 0x60) >> 3); // 0, 4, or 8
|
|
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 & 0x60) >> 3; // 0, 4 or 8
|
|
|
|
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(am_hal_gpio_mask_t *pGpioIntMask)
|
|
{
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
if ( pGpioIntMask->U.Msk[AM_HAL_GPIO_MAX_PADS / 32] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS % 32)) - 1) )
|
|
{
|
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
|
}
|
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
//
|
|
// Enable the interrupts.
|
|
//
|
|
AM_CRITICAL_BEGIN
|
|
|
|
DIAG_SUPPRESS_VOLATILE_ORDER()
|
|
GPIO->INT0EN |= pGpioIntMask->U.Msk[0];
|
|
GPIO->INT1EN |= pGpioIntMask->U.Msk[1];
|
|
GPIO->INT2EN |= pGpioIntMask->U.Msk[2];
|
|
DIAG_DEFAULT_VOLATILE_ORDER()
|
|
|
|
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(am_hal_gpio_mask_t *pGpioIntMask)
|
|
{
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
if ( !pGpioIntMask )
|
|
{
|
|
return AM_HAL_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if ( pGpioIntMask->U.Msk[AM_HAL_GPIO_MAX_PADS / 32] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS % 32)) - 1) )
|
|
{
|
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
|
}
|
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
//
|
|
// Disable the interrupts.
|
|
//
|
|
AM_CRITICAL_BEGIN
|
|
|
|
DIAG_SUPPRESS_VOLATILE_ORDER()
|
|
GPIO->INT0EN &= ~pGpioIntMask->U.Msk[0];
|
|
GPIO->INT1EN &= ~pGpioIntMask->U.Msk[1];
|
|
GPIO->INT2EN &= ~pGpioIntMask->U.Msk[2];
|
|
DIAG_DEFAULT_VOLATILE_ORDER()
|
|
|
|
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(am_hal_gpio_mask_t *pGpioIntMask)
|
|
{
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
if ( !pGpioIntMask )
|
|
{
|
|
return AM_HAL_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if ( pGpioIntMask->U.Msk[AM_HAL_GPIO_MAX_PADS / 32] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS % 32)) - 1) )
|
|
{
|
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
|
}
|
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
//
|
|
// Clear the interrupts.
|
|
//
|
|
AM_CRITICAL_BEGIN
|
|
|
|
DIAG_SUPPRESS_VOLATILE_ORDER()
|
|
GPIO->INT0CLR |= pGpioIntMask->U.Msk[0];
|
|
GPIO->INT1CLR |= pGpioIntMask->U.Msk[1];
|
|
GPIO->INT2CLR |= pGpioIntMask->U.Msk[2];
|
|
DIAG_DEFAULT_VOLATILE_ORDER()
|
|
|
|
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,
|
|
am_hal_gpio_mask_t *pGpioIntMask)
|
|
{
|
|
volatile uint32_t ui32Mask[3];
|
|
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
if ( !pGpioIntMask )
|
|
{
|
|
return AM_HAL_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if ( pGpioIntMask->U.Msk[AM_HAL_GPIO_MAX_PADS / 32] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS % 32)) - 1) )
|
|
{
|
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
|
}
|
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
//
|
|
// Initialize mask variable outside critical section
|
|
//
|
|
ui32Mask[0] = 0xFFFFFFFF;
|
|
ui32Mask[1] = 0xFFFFFFFF;
|
|
ui32Mask[2] = 0xFFFFFFFF;
|
|
|
|
//
|
|
// Combine upper or lower GPIO words into one 64 bit return value.
|
|
//
|
|
AM_CRITICAL_BEGIN
|
|
|
|
DIAG_SUPPRESS_VOLATILE_ORDER()
|
|
if ( bEnabledOnly )
|
|
{
|
|
ui32Mask[0] = GPIO->INT0EN;
|
|
ui32Mask[1] = GPIO->INT1EN;
|
|
ui32Mask[2] = GPIO->INT2EN;
|
|
}
|
|
|
|
pGpioIntMask->U.Msk[0] = GPIO->INT0STAT & ui32Mask[0];
|
|
pGpioIntMask->U.Msk[1] = GPIO->INT1STAT & ui32Mask[1];
|
|
pGpioIntMask->U.Msk[2] = GPIO->INT2STAT & ui32Mask[2];
|
|
DIAG_DEFAULT_VOLATILE_ORDER()
|
|
|
|
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-73) 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 > 73.
|
|
//
|
|
//*****************************************************************************
|
|
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(am_hal_gpio_mask_t *pGpioIntMaskStatus)
|
|
{
|
|
uint32_t ui32RetStatus = AM_HAL_STATUS_SUCCESS;
|
|
uint32_t ui32Status, ui32FFS, ui32Idx;
|
|
am_hal_gpio_handler_t pfnHandler;
|
|
uint32_t *pui32Status;
|
|
|
|
#ifndef AM_HAL_DISABLE_API_VALIDATION
|
|
if ( !pGpioIntMaskStatus )
|
|
{
|
|
return AM_HAL_STATUS_INVALID_ARG;
|
|
}
|
|
|
|
if ( pGpioIntMaskStatus->U.Msk[AM_HAL_GPIO_MAX_PADS / 32] &
|
|
~(((uint32_t)1 << (AM_HAL_GPIO_MAX_PADS % 32)) - 1) )
|
|
{
|
|
return AM_HAL_STATUS_OUT_OF_RANGE;
|
|
}
|
|
#endif // AM_HAL_DISABLE_API_VALIDATION
|
|
|
|
//
|
|
// Convert the mask status structure to an uint32_t pointer.
|
|
//
|
|
pui32Status = (uint32_t*)pGpioIntMaskStatus;
|
|
|
|
//
|
|
// Handle interrupts.
|
|
//
|
|
uint32_t ui32regcnt = AM_HAL_GPIO_NUMWORDS;
|
|
ui32Idx = 0;
|
|
while ( ui32regcnt )
|
|
{
|
|
//
|
|
// Get next status word from the caller.
|
|
//
|
|
ui32Status = *pui32Status++;
|
|
|
|
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);
|
|
ui32FFS = 31 - AM_ASM_CLZ(ui32FFS);
|
|
|
|
//
|
|
// 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[ui32Idx + 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[ui32Idx + ui32FFS]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No handler was registered for the GPIO that interrupted.
|
|
// Return an error.
|
|
//
|
|
ui32RetStatus = AM_HAL_STATUS_INVALID_OPERATION;
|
|
}
|
|
}
|
|
--ui32regcnt;
|
|
ui32Idx += 32;
|
|
}
|
|
|
|
//
|
|
// Return the status.
|
|
//
|
|
return ui32RetStatus;
|
|
|
|
} // am_hal_gpio_interrupt_service()
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// End Doxygen group.
|
|
//! @}
|
|
//
|
|
//*****************************************************************************
|