rt-thread-official/bsp/efm32/EFM32GG_DK3750/dvk.c

577 lines
18 KiB
C

/**************************************************************************//**
* @file
* @brief EFM32GG_DK3750 board support package
* @author Energy Micro AS
* @version 2.0.1
******************************************************************************
* @section License
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
* microcontrollers and "EFR4" radios.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
* obligation to support this Software. Energy Micro AS is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Energy Micro AS will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
*****************************************************************************/
/**************************************************************************//**
* @addtogroup BSP
* @{
*****************************************************************************/
#include "efm32.h"
#include "em_gpio.h"
#include "em_cmu.h"
#include "em_usart.h"
#include "dvk.h"
#include "dvk_bcregisters.h"
/** Keep intialization mode */
DVK_Init_TypeDef dvkOperationMode;
/**************************************************************************//**
* @brief Initialize EFM32GG_DK3750 board support package functionality
* @param[in] mode Initialize in EBI or SPI mode
*****************************************************************************/
void DVK_init(DVK_Init_TypeDef mode)
{
bool ret = false;
if (mode == DVK_Init_EBI)
{
dvkOperationMode = mode;
DVK_busControlMode(DVK_BusControl_EBI);
ret = DVK_EBI_init();
}
if (mode == DVK_Init_SPI)
{
dvkOperationMode = mode;
DVK_busControlMode(DVK_BusControl_SPI);
ret = DVK_SPI_init();
}
if (ret == false)
{
/* Unable to access board control, this is an abornomal situation. */
/* Try to restart kit and reprogram EFM32 with a standard example */
/* as this is most likely caused by a peripheral misconfiguration. */
while (1) ;
}
DVK_setEnergyMode(0);
}
/**************************************************************************//**
* @brief Disable EFM32GG_DK3750 board support package functionality
*****************************************************************************/
void DVK_disable(void)
{
if (dvkOperationMode == DVK_Init_EBI)
{
DVK_EBI_disable();
}
if (dvkOperationMode == DVK_Init_SPI)
{
DVK_SPI_disable();
}
DVK_busControlMode(DVK_BusControl_OFF);
}
/**************************************************************************//**
* @brief Configure Board Controller bus decode logic
* @param[in] mode Mode of operation for decode logic
*****************************************************************************/
void DVK_busControlMode(DVK_BusControl_TypeDef mode)
{
/* Configure GPIO pins for Board Bus mode */
/* Note: Inverter on GPIO lines to BC, so signals are active low */
CMU_ClockEnable(cmuClock_GPIO, true);
switch (mode)
{
case DVK_BusControl_OFF:
/* Configure board for OFF mode on PB15 MCU_EBI_CONNECT */
GPIO_PinModeSet(gpioPortB, 15, gpioModePushPull, 1);
/* Configure board for OFF mode on PD13 MCU_SPI_CONNECT */
GPIO_PinModeSet(gpioPortD, 13, gpioModePushPull, 1);
break;
case DVK_BusControl_DIRECT:
/* Configure board for DIRECT on PB15 MCU_EBI_CONNECT */
GPIO_PinModeSet(gpioPortB, 15, gpioModePushPull, 0);
/* Configure board for DIRECT on PD13 MCU_SPI_CONNECT */
GPIO_PinModeSet(gpioPortD, 13, gpioModePushPull, 0);
break;
case DVK_BusControl_SPI:
/* Configure board for SPI mode on PB15 MCU_EBI_CONNECT */
GPIO_PinModeSet(gpioPortB, 15, gpioModePushPull, 1);
/* Configure board for SPI mode on PD13 MCU_SPI_CONNECT */
GPIO_PinModeSet(gpioPortD, 13, gpioModePushPull, 0);
break;
case DVK_BusControl_EBI:
default:
/* Configure board for EBI mode on PB15 MCU_EBI_CONNECT */
GPIO_PinModeSet(gpioPortB, 15, gpioModePushPull, 0);
/* Configure board for EBI mode on PD13 MCU_SPI_CONNECT */
GPIO_PinModeSet(gpioPortD, 13, gpioModePushPull, 1);
break;
}
}
/**************************************************************************//**
* @brief Set board LEDs
*
* @param[in] leds
* 16 bits enabling or disabling individual board LEDs
*****************************************************************************/
void DVK_setLEDs(uint16_t leds)
{
DVK_writeRegister(&BC_REGISTER->UIF_LEDS, leds);
}
/**************************************************************************//**
* @brief Get board LED configuration
*
* @return
* 16 bits of LED status
*****************************************************************************/
uint16_t DVK_getLEDs(void)
{
return DVK_readRegister(&BC_REGISTER->UIF_LEDS);
}
/**************************************************************************//**
* @brief DK3750 Peripheral Access Control
* Enable or disable access to on-board peripherals through switches
* and SPI switch where applicable. Turn off conflicting peripherals when
* enabling another.
* @param[in] perf
* Which peripheral to configure
* @param[in] enable
* If true, sets up access to peripheral, if false disables it
*****************************************************************************/
void DVK_peripheralAccess(DVK_Peripheral_TypeDef perf, bool enable)
{
uint16_t perfControl;
perfControl = DVK_readRegister(&BC_REGISTER->PERICON);
/* Enable or disable the specificed peripheral by setting board control switch */
if (enable)
{
switch (perf)
{
case DVK_RS232_SHUTDOWN:
perfControl |= (1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
break;
case DVK_RS232_UART:
perfControl &= ~(1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
perfControl &= ~(1 << BC_PERICON_RS232_LEUART_SHIFT);
perfControl |= (1 << BC_PERICON_RS232_UART_SHIFT);
break;
case DVK_RS232_LEUART:
perfControl &= ~(1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
perfControl &= ~(1 << BC_PERICON_RS232_UART_SHIFT);
perfControl |= (1 << BC_PERICON_RS232_LEUART_SHIFT);
break;
case DVK_I2C:
perfControl |= (1 << BC_PERICON_I2C_SHIFT);
break;
case DVK_ETH:
/* Enable SPI interface */
DVK_spiControl(DVK_SPI_Ethernet);
/* Enable Ethernet analog switches */
perfControl |= (1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl |= (1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
/* Disable Analog Diff Input - pins PD0 and PD1 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_DIFF_SHIFT);
/* Disable Touch Inputs - pin PD3 is shared */
perfControl &= ~(1 << BC_PERICON_TOUCH_SHIFT);
/* Disable Analog SE Input - pin PD2 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_SE_SHIFT);
break;
case DVK_I2S:
/* Direct SPI interface to I2S DAC */
DVK_spiControl(DVK_SPI_Audio);
/* Also make surea Audio out is connected for I2S operation */
perfControl |= (1 << BC_PERICON_AUDIO_OUT_SHIFT);
perfControl |= (1 << BC_PERICON_AUDIO_OUT_SEL_SHIFT);
perfControl |= (1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
/* Disable Analog Diff Input - pins PD0 and PD1 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_DIFF_SHIFT);
/* Disable Touch Inputs - pin PD3 is shared */
perfControl &= ~(1 << BC_PERICON_TOUCH_SHIFT);
/* Disable Analog SE Input - pin PD2 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_SE_SHIFT);
break;
case DVK_TRACE:
perfControl |= (1 << BC_PERICON_TRACE_SHIFT);
break;
case DVK_TOUCH:
perfControl |= (1 << BC_PERICON_TOUCH_SHIFT);
/* Disconnect SPI switch, pin PD3 is shared */
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
case DVK_AUDIO_IN:
perfControl |= (1 << BC_PERICON_AUDIO_IN_SHIFT);
break;
case DVK_AUDIO_OUT:
perfControl &= ~(1 << BC_PERICON_AUDIO_OUT_SEL_SHIFT);
perfControl |= (1 << BC_PERICON_AUDIO_OUT_SHIFT);
break;
case DVK_ANALOG_DIFF:
perfControl |= (1 << BC_PERICON_ANALOG_DIFF_SHIFT);
/* Disconnect SPI switch, pin PD0 and PD1 is shared */
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
case DVK_ANALOG_SE:
perfControl |= (1 << BC_PERICON_ANALOG_SE_SHIFT);
/* Disconnect SPI switch, pin PD2 is shared */
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
case DVK_MICROSD:
perfControl |= (1 << BC_PERICON_SPI_SHIFT);
break;
case DVK_TFT:
/* Enable SPI to SSD2119 */
DVK_spiControl(DVK_SPI_Display);
/* Enable SPI analog switch */
perfControl |= (1 << BC_PERICON_I2S_ETH_SHIFT);
/* Disable Analog Diff Input - pins D0 and D1 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_DIFF_SHIFT);
/* Disable Touch Inputs - pin D3 is shared */
perfControl &= ~(1 << BC_PERICON_TOUCH_SHIFT);
/* Disable Analog SE Input - pin D2 is shared */
perfControl &= ~(1 << BC_PERICON_ANALOG_SE_SHIFT);
break;
}
}
else
{
switch (perf)
{
case DVK_RS232_SHUTDOWN:
perfControl &= ~(1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
break;
case DVK_RS232_UART:
perfControl |= (1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
perfControl &= ~(1 << BC_PERICON_RS232_UART_SHIFT);
break;
case DVK_RS232_LEUART:
perfControl |= (1 << BC_PERICON_RS232_SHUTDOWN_SHIFT);
perfControl &= ~(1 << BC_PERICON_RS232_LEUART_SHIFT);
break;
case DVK_I2C:
perfControl &= ~(1 << BC_PERICON_I2C_SHIFT);
break;
case DVK_ETH:
/* Disable SPI interface */
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
case DVK_I2S:
/* Disable SPI interface and audio out */
perfControl &= ~(1 << BC_PERICON_AUDIO_OUT_SHIFT);
perfControl &= ~(1 << BC_PERICON_AUDIO_OUT_SEL_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
case DVK_TRACE:
perfControl &= ~(1 << BC_PERICON_TRACE_SHIFT);
break;
case DVK_TOUCH:
perfControl &= ~(1 << BC_PERICON_TOUCH_SHIFT);
break;
case DVK_AUDIO_IN:
perfControl &= ~(1 << BC_PERICON_AUDIO_IN_SHIFT);
break;
case DVK_AUDIO_OUT:
perfControl &= ~(1 << BC_PERICON_AUDIO_OUT_SEL_SHIFT);
perfControl &= ~(1 << BC_PERICON_AUDIO_OUT_SHIFT);
break;
case DVK_ANALOG_DIFF:
perfControl &= ~(1 << BC_PERICON_ANALOG_DIFF_SHIFT);
break;
case DVK_ANALOG_SE:
perfControl &= ~(1 << BC_PERICON_ANALOG_SE_SHIFT);
break;
case DVK_MICROSD:
perfControl &= ~(1 << BC_PERICON_SPI_SHIFT);
break;
case DVK_TFT:
/* Disable SPI interface */
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SHIFT);
perfControl &= ~(1 << BC_PERICON_I2S_ETH_SEL_SHIFT);
DVK_spiControl(DVK_SPI_OFF);
break;
}
}
/* Write back register */
DVK_writeRegister(&BC_REGISTER->PERICON, perfControl);
}
/**************************************************************************//**
* @brief Get status of push buttons on kit
*
* @return
* Button state, each bit representing each push button PB0-PB4
*****************************************************************************/
uint16_t DVK_getPushButtons(void)
{
uint16_t tmp;
tmp = DVK_readRegister(&BC_REGISTER->UIF_PB);
return (~tmp) & 0x000F;
}
/**************************************************************************//**
* @brief Configure SPI for correct peripheral
*
* @param[in] device
* Device to enable SPI bus for
*****************************************************************************/
void DVK_spiControl(DVK_SpiControl_TypeDef device)
{
switch (device)
{
case DVK_SPI_Audio:
DVK_writeRegister(&BC_REGISTER->SPI_DEMUX, BC_SPI_DEMUX_SLAVE_AUDIO);
break;
case DVK_SPI_Ethernet:
DVK_writeRegister(&BC_REGISTER->SPI_DEMUX, BC_SPI_DEMUX_SLAVE_ETHERNET);
break;
case DVK_SPI_Display:
DVK_writeRegister(&BC_REGISTER->SPI_DEMUX, BC_SPI_DEMUX_SLAVE_DISPLAY);
break;
case DVK_SPI_OFF:
USART_Reset(USART1);
CMU_ClockEnable(cmuClock_USART1, false);
break;
}
}
/**************************************************************************//**
* @brief Inform AEM/Board Controller about what energy mode we are currently
* entering. This information can be used for better visual feedback of
* EFM32GG activity for the board controller and PC applications
* @param energyMode What energy mode we are going to use next
*****************************************************************************/
void DVK_setEnergyMode(uint16_t energyMode)
{
DVK_writeRegister(&BC_REGISTER->EM, energyMode);
}
/**************************************************************************//**
* @brief Enable "Control" buttons/joystick/dip switch interrupts
* @param flags Board control interrupt flags, INTEN_<something>
*****************************************************************************/
void DVK_enableInterrupt(uint16_t flags)
{
uint16_t tmp;
/* Add flags to interrupt enable register */
tmp = DVK_readRegister(&BC_REGISTER->INTEN);
tmp |= flags;
DVK_writeRegister(&BC_REGISTER->INTEN, tmp);
}
/**************************************************************************//**
* @brief Disable "Control" buttons/joystick/dip switch interrupts
* @param flags Board control interrupt flags, BC_INTEN_<something>
*****************************************************************************/
void DVK_disableInterrupt(uint16_t flags)
{
uint16_t tmp;
/* Clear flags from interrupt enable register */
tmp = DVK_readRegister(&BC_REGISTER->INTEN);
flags = ~(flags);
tmp &= flags;
DVK_writeRegister(&BC_REGISTER->INTEN, tmp);
}
/**************************************************************************//**
* @brief Clear interrupts
* @param flags Board control interrupt flags, BC_INTEN_<something>
*****************************************************************************/
void DVK_clearInterruptFlags(uint16_t flags)
{
uint16_t tmp;
tmp = DVK_readRegister(&BC_REGISTER->INTFLAG);
tmp &= ~(flags);
DVK_writeRegister(&BC_REGISTER->INTFLAG, tmp);
}
/**************************************************************************//**
* @brief Read interrupt flags
* @return Returns currently triggered interrupts
*****************************************************************************/
uint16_t DVK_getInterruptFlags(void)
{
return DVK_readRegister(&BC_REGISTER->INTFLAG);
}
/**************************************************************************//**
* @brief Get joystick button status
* @return Joystick controller status
*****************************************************************************/
uint16_t DVK_getJoystick(void)
{
uint16_t joyStick = 0;
joyStick = ~(DVK_readRegister(&BC_REGISTER->UIF_JOYSTICK)) & 0x001f;
return joyStick;
}
/**************************************************************************//**
* @brief Get dipswitch status
* The DIP switches are free for user programmable purposes
* @return Dip switch
*****************************************************************************/
uint16_t DVK_getDipSwitch(void)
{
return DVK_readRegister(&BC_REGISTER->UIF_DIP) & 0x000f;
}
/**************************************************************************//**
* @brief Configure display control
*****************************************************************************/
void DVK_displayControl(DVK_Display_TypeDef option)
{
uint16_t tmp;
switch (option)
{
case DVK_Display_EBI:
DVK_writeRegister(&BC_REGISTER->ARB_CTRL, BC_ARB_CTRL_EBI);
break;
case DVK_Display_SPI:
DVK_writeRegister(&BC_REGISTER->ARB_CTRL, BC_ARB_CTRL_SPI);
break;
case DVK_Display_BC:
DVK_writeRegister(&BC_REGISTER->ARB_CTRL, BC_ARB_CTRL_BC);
break;
case DVK_Display_PowerEnable:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp |= (BC_DISPLAY_CTRL_POWER_ENABLE);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
case DVK_Display_PowerDisable:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp &= ~(BC_DISPLAY_CTRL_POWER_ENABLE);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
case DVK_Display_ResetAssert:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp |= (BC_DISPLAY_CTRL_RESET);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
case DVK_Display_ResetRelease:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp &= ~(BC_DISPLAY_CTRL_RESET);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
case DVK_Display_Mode8080:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp &= ~(BC_DISPLAY_CTRL_MODE_GENERIC);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
case DVK_Display_ModeGeneric:
tmp = DVK_readRegister(&BC_REGISTER->DISPLAY_CTRL);
tmp |= (BC_DISPLAY_CTRL_MODE_GENERIC);
DVK_writeRegister(&BC_REGISTER->DISPLAY_CTRL, tmp);
break;
default:
/* Unknown command */
while (1) ;
}
}
/** @} (end group BSP) */