/**
******************************************************************************
* @file usb_pwr.c
* @author MCD Application Team
* @version V4.0.0
* @date 21-January-2013
* @brief Connection/disconnection & power management
******************************************************************************
* @attention
*
*
© COPYRIGHT 2013 STMicroelectronics
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
#include "usb_lib.h"
#include "usb_conf.h"
#include "usb_pwr.h"
#include "hw_config.h"
// Private variables
__IO uint32_t bDeviceState = UNCONNECTED; // USB device status
__IO bool fSuspendEnabled = TRUE; // true when suspend is possible
__IO uint32_t remotewakeupon = 0; // Remote wake-up state machine
__IO uint32_t EP[8]; // Array to store endpoint registers
// Private structures
struct {
__IO RESUME_STATE eState;
__IO uint8_t bESOFcnt;
} ResumeS;
/*******************************************************************************
* Function Name : PowerOn
* Description :
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
RESULT PowerOn(void) {
// cable plugged-in ?
SYSCFG_USBPuCmd(ENABLE);
// CNTR_PWDN = 0
*CNTR = CNTR_FRES;
// CNTR_FRES = 0
*CNTR = 0;
// Clear pending interrupts
*ISTR = 0;
// Set interrupt mask
*CNTR = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : PowerOff
* Description : handles switch-off conditions
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
RESULT PowerOff() {
// disable all interrupts and force USB reset
*CNTR = CNTR_FRES;
// clear interrupt status register
*ISTR = 0;
// Disable the Pull-Up
SYSCFG_USBPuCmd(DISABLE);
// switch-off device
*CNTR = CNTR_FRES | CNTR_PDWN;
// sw variables reset
// ...
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : Suspend
* Description : sets suspend mode operating conditions
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
void Suspend(void) {
uint32_t i;
__IO uint32_t savePWR_CR;
// suspend preparation
// ...
// This a sequence to apply a force RESET to handle a robustness case
// Store endpoints registers status
for (i = 0; i < 8; i++) EP[i] = _GetENDPOINT(i);
// unmask RESET flag and apply FRES
*CNTR |= CNTR_RESETM | CNTR_FRES;
// clear FRES
*CNTR &= ~CNTR_FRES;
// poll for RESET flag in ISTR
while (!(*ISTR & ISTR_RESET));
// clear RESET flag in ISTR
*ISTR = CLR_RESET;
// restore enpoints
for (i=0; i < 8; i++) _SetENDPOINT(i,EP[i]);
// Now it is safe to enter macrocell in suspend mode
*CNTR |= CNTR_FSUSP;
// force low-power mode in the macrocell
*CNTR |= CNTR_LPMODE;
// prepare entry in low power mode (STOP mode)
// Select the regulator state in STOP mode
savePWR_CR = PWR->CR;
PWR->CR &= (uint32_t)0xFFFFFFFC; // Clear PDDS and LPDS bits
PWR->CR |= PWR_Regulator_LowPower; // Set LPDS bit according to PWR_Regulator value
// Set SLEEPDEEP bit of Cortex-M System Control Register
SCB->SCR |= SCB_SCR_SLEEPDEEP;
// enter system in STOP mode, only when wake-up flag in not set
if (!(*ISTR & ISTR_WKUP)) {
__WFI();
// Reset SLEEPDEEP bit of Cortex-M System Control Register
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);
} else {
// Clear Wakeup flag
*ISTR = CLR_WKUP;
// clear FSUSP to abort entry in suspend mode
*CNTR &= ~CNTR_FSUSP;
// restore sleep mode configuration
// restore Power regulator config in sleep mode
PWR->CR = savePWR_CR;
// Reset SLEEPDEEP bit of Cortex-M System Control Register
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);
}
}
/*******************************************************************************
* Function Name : Resume_Init
* Description : Handles wake-up restoring normal operations
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
void Resume_Init(void) {
// ------------------ ONLY WITH BUS-POWERED DEVICES ----------------------
// restart the clocks
// ...
// CNTR_LPMODE = 0
*CNTR &= ~CNTR_LPMODE;
// restore full power ... on connected devices
Leave_LowPowerMode();
// reset FSUSP bit
*CNTR = IMR_MSK;
// reverse suspend preparation
// ...
}
/*******************************************************************************
* Function Name : Resume
* Description : This is the state machine handling resume operations and
* timing sequence. The control is based on the Resume structure
* variables and on the ESOF interrupt calling this subroutine
* without changing machine state.
* Input : a state machine value (RESUME_STATE)
* RESUME_ESOF doesn't change ResumeS.eState allowing
* decrementing of the ESOF counter in different states.
* Output : None.
* Return : None.
*******************************************************************************/
void Resume(RESUME_STATE eResumeSetVal) {
if (eResumeSetVal != RESUME_ESOF) ResumeS.eState = eResumeSetVal;
switch (ResumeS.eState) {
case RESUME_EXTERNAL:
if (remotewakeupon == 0) {
Resume_Init();
ResumeS.eState = RESUME_OFF;
} else {
// RESUME detected during the RemoteWAkeup signalling => keep RemoteWakeup handling
ResumeS.eState = RESUME_ON;
}
break;
case RESUME_INTERNAL:
Resume_Init();
ResumeS.eState = RESUME_START;
remotewakeupon = 1;
break;
case RESUME_LATER:
ResumeS.bESOFcnt = 2;
ResumeS.eState = RESUME_WAIT;
break;
case RESUME_WAIT:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) ResumeS.eState = RESUME_START;
break;
case RESUME_START:
*CNTR |= CNTR_RESUME;
ResumeS.eState = RESUME_ON;
ResumeS.bESOFcnt = 10;
break;
case RESUME_ON:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
*CNTR &= ~CNTR_RESUME;
ResumeS.eState = RESUME_OFF;
remotewakeupon = 0;
}
break;
case RESUME_OFF:
case RESUME_ESOF:
default:
ResumeS.eState = RESUME_OFF;
break;
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/