From 51e59995837219d3be6b04fc67f92e2fb7c8ab85 Mon Sep 17 00:00:00 2001 From: jnosky Date: Sat, 12 Nov 2011 16:22:03 -0500 Subject: [PATCH] Added STM32F4 discovery demo sources and make file --- .../stm32f4/Projects/discovery_demo/Makefile | 61 + .../discovery_demo/Release_Notes.html | 151 ++ .../discovery_demo/STM32F4-Discovery_Demo.bin | Bin 0 -> 31620 bytes .../discovery_demo/STM32F4-Discovery_Demo.elf | Bin 0 -> 243590 bytes .../stm32f4/Projects/discovery_demo/main.c | 509 ++++ .../stm32f4/Projects/discovery_demo/main.h | 62 + .../Projects/discovery_demo/selftest.c | 808 ++++++ .../Projects/discovery_demo/selftest.h | 41 + .../discovery_demo/startup_stm32f4xx.s | 509 ++++ .../Projects/discovery_demo/stm32_flash.ld | 170 ++ .../Projects/discovery_demo/stm32f4xx_conf.h | 94 + .../Projects/discovery_demo/stm32f4xx_it.c | 320 +++ .../Projects/discovery_demo/stm32f4xx_it.h | 54 + .../discovery_demo/system_stm32f4xx.c | 566 +++++ .../stm32f4/Projects/discovery_demo/usb_bsp.c | 382 +++ .../Projects/discovery_demo/usb_conf.h | 252 ++ .../Projects/discovery_demo/usb_core.c | 2187 +++++++++++++++++ .../Projects/discovery_demo/usb_core.h | 408 +++ .../Projects/discovery_demo/usbd_conf.h | 93 + .../Projects/discovery_demo/usbd_desc.c | 313 +++ .../Projects/discovery_demo/usbd_desc.h | 114 + .../Projects/discovery_demo/usbd_usr.c | 238 ++ 22 files changed, 7332 insertions(+) create mode 100644 example/stm32f4/Projects/discovery_demo/Makefile create mode 100644 example/stm32f4/Projects/discovery_demo/Release_Notes.html create mode 100644 example/stm32f4/Projects/discovery_demo/STM32F4-Discovery_Demo.bin create mode 100644 example/stm32f4/Projects/discovery_demo/STM32F4-Discovery_Demo.elf create mode 100644 example/stm32f4/Projects/discovery_demo/main.c create mode 100644 example/stm32f4/Projects/discovery_demo/main.h create mode 100644 example/stm32f4/Projects/discovery_demo/selftest.c create mode 100644 example/stm32f4/Projects/discovery_demo/selftest.h create mode 100644 example/stm32f4/Projects/discovery_demo/startup_stm32f4xx.s create mode 100644 example/stm32f4/Projects/discovery_demo/stm32_flash.ld create mode 100644 example/stm32f4/Projects/discovery_demo/stm32f4xx_conf.h create mode 100644 example/stm32f4/Projects/discovery_demo/stm32f4xx_it.c create mode 100644 example/stm32f4/Projects/discovery_demo/stm32f4xx_it.h create mode 100644 example/stm32f4/Projects/discovery_demo/system_stm32f4xx.c create mode 100644 example/stm32f4/Projects/discovery_demo/usb_bsp.c create mode 100644 example/stm32f4/Projects/discovery_demo/usb_conf.h create mode 100644 example/stm32f4/Projects/discovery_demo/usb_core.c create mode 100644 example/stm32f4/Projects/discovery_demo/usb_core.h create mode 100644 example/stm32f4/Projects/discovery_demo/usbd_conf.h create mode 100644 example/stm32f4/Projects/discovery_demo/usbd_desc.c create mode 100644 example/stm32f4/Projects/discovery_demo/usbd_desc.h create mode 100644 example/stm32f4/Projects/discovery_demo/usbd_usr.c diff --git a/example/stm32f4/Projects/discovery_demo/Makefile b/example/stm32f4/Projects/discovery_demo/Makefile new file mode 100644 index 0000000..782f982 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/Makefile @@ -0,0 +1,61 @@ +EXECUTABLE=STM32F4-Discovery_Demo.elf +BIN_IMAGE=STM32F4-Discovery_Demo.bin + +CC=arm-none-eabi-gcc +OBJCOPY=arm-none-eabi-objcopy + +CFLAGS=-g -O2 -mlittle-endian -mthumb +CFLAGS+=-mcpu=cortex-m4 +CFLAGS+=-ffreestanding -nostdlib + +#usb_conf.h +CFLAGS+=-DUSE_USB_OTG_FS=1 + +# to run from FLASH +CFLAGS+=-Wl,-T,stm32_flash.ld + +CFLAGS+=-I./ + +# stm32f4_discovery lib +CFLAGS+=-I../../STM32F4xx_StdPeriph_Driver/inc +CFLAGS+=-I../../STM32F4xx_StdPeriph_Driver/inc/device_support +CFLAGS+=-I../../STM32F4xx_StdPeriph_Driver/inc/core_support + +#STM32_USB_Device_Library +CFLAGS+=-I../../STM32_USB_Device_Library/Class/hid/inc +CFLAGS+=-I../../STM32_USB_Device_Library/Core/inc + +#STM32_USB_OTG_Driver +CFLAGS+=-I../../STM32_USB_OTG_Driver/inc + +#STM32F4xx_StdPeriph_Driver\inc +CFLAGS+=-I../../STM32F4xx_StdPeriph_Driver/inc + +#Utilities +CFLAGS+=-I../../Utilities/STM32F4-Discovery + +all: $(BIN_IMAGE) + +$(BIN_IMAGE): $(EXECUTABLE) + $(OBJCOPY) -O binary $^ $@ + +$(EXECUTABLE): main.c selftest.c system_stm32f4xx.c startup_stm32f4xx.s stm32f4xx_it.c \ + usb_bsp.c usbd_desc.c usbd_usr.c usb_core.c \ + ../../Utilities/STM32F4-Discovery/stm32f4_discovery.c \ + ../../Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.c \ + ../../Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c \ + ../../STM32_USB_OTG_Driver/src/usb_dcd_int.c \ + ../../STM32_USB_OTG_Driver/src/usb_dcd.c \ + ../../STM32_USB_Device_Library/core/src/usbd_core.c \ + ../../STM32_USB_Device_Library/core/src/usbd_req.c \ + ../../STM32_USB_Device_Library/core/src/usbd_ioreq.c \ + ../../STM32_USB_Device_Library/class/hid/src/usbd_hid_core.c \ + + + $(CC) $(CFLAGS) $^ -o $@ -L../../STM32F4xx_StdPeriph_Driver/build -lSTM32F4xx_StdPeriph_Driver -L../../STM32F_USB_OTG_Driver/build + +clean: + rm -rf $(EXECUTABLE) + rm -rf $(BIN_IMAGE) + +.PHONY: all clean diff --git a/example/stm32f4/Projects/discovery_demo/Release_Notes.html b/example/stm32f4/Projects/discovery_demo/Release_Notes.html new file mode 100644 index 0000000..304ad5d --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/Release_Notes.html @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + Release Notes for STM32F4-Discovery Board Demonstration firmware + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F4-Discovery Board Demonstration firmware

+

Copyright +2011 STMicroelectronics

+

+
+

 

+ + + + + + +
+

Contents

+
    +
  1. STM32F4-Discovery Board Demonstration firmware update History
  2. +
  3. License
  4. +
+ + +

STM32F4-Discovery Board Demonstration firmware update History

For more information on the STM32F4-Discovery board visit www.st.com/stm32f4-discovery.

V1.0.0 / 19-September-2011

+

Main +Changes

+ +
  • First official version of the STM32F4-Discovery Board Demonstration firmware

License

+

The +enclosed firmware and all the related documentation are not covered by +a License Agreement, if you need such License you can contact your +local STMicroelectronics office.

+ + THE +PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO +SAVE TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR +ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY +CLAIMS ARISING FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY +CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH +THEIR PRODUCTS. + +
+
+

For +complete documentation on STMicroelectronics Microcontrollers visit www.st.com

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/example/stm32f4/Projects/discovery_demo/STM32F4-Discovery_Demo.bin b/example/stm32f4/Projects/discovery_demo/STM32F4-Discovery_Demo.bin new file mode 100644 index 0000000000000000000000000000000000000000..9635fb22d88868054c6472e6806c45b4a14e23c0 GIT binary patch literal 31620 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�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

FC?d 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 literal 0 HcmV?d00001 diff --git a/example/stm32f4/Projects/discovery_demo/main.c b/example/stm32f4/Projects/discovery_demo/main.c new file mode 100644 index 0000000..b7d92ed --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/main.c @@ -0,0 +1,509 @@ +/** + ****************************************************************************** + * @file main.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief Main program body + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "usbd_hid_core.h" +#include "usbd_usr.h" +#include "usbd_desc.h" + +//Library config for this project!!!!!!!!!!! +#include "stm32f4xx_conf.h" + +/** @addtogroup STM32F4-Discovery_Demo + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +#define TESTRESULT_ADDRESS 0x080FFFFC +#define ALLTEST_PASS 0x00000000 +#define ALLTEST_FAIL 0x55555555 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment = 4 + #endif +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ +__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END; + +uint16_t PrescalerValue = 0; + +__IO uint32_t TimingDelay; +__IO uint8_t DemoEnterCondition = 0x00; +__IO uint8_t UserButtonPressed = 0x00; +LIS302DL_InitTypeDef LIS302DL_InitStruct; +LIS302DL_FilterConfigTypeDef LIS302DL_FilterStruct; +__IO int8_t X_Offset, Y_Offset, Z_Offset = 0x00; +uint8_t Buffer[6]; + +/* Private function prototypes -----------------------------------------------*/ +static uint32_t Demo_USBConfig(void); +static void TIM4_Config(void); +static void Demo_Exec(void); + +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Main program. + * @param None + * @retval None + */ +int main(void) +{ + RCC_ClocksTypeDef RCC_Clocks; + + /* Initialize LEDs and User_Button on STM32F4-Discovery --------------------*/ + STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_EXTI); + + STM_EVAL_LEDInit(LED4); + STM_EVAL_LEDInit(LED3); + STM_EVAL_LEDInit(LED5); + STM_EVAL_LEDInit(LED6); + + /* SysTick end of count event each 10ms */ + RCC_GetClocksFreq(&RCC_Clocks); + SysTick_Config(RCC_Clocks.HCLK_Frequency / 100); + + if (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET) + { + /* Turn on LEDs available on STM32F4-Discovery ---------------------------*/ + STM_EVAL_LEDOn(LED4); + STM_EVAL_LEDOn(LED3); + STM_EVAL_LEDOn(LED5); + STM_EVAL_LEDOn(LED6); + + if ((*(__IO uint32_t*) TESTRESULT_ADDRESS) == ALLTEST_PASS) + { + TimingDelay = 300; + /* Waiting User Button is pressed or Test Program condition verified */ + while ((STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET)&&(TimingDelay != 0x00)) + {} + } + else + { + /* Waiting User Button is Released or TimeOut*/ + TimingDelay = 300; + while ((STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET)&&(TimingDelay != 0x00)) + {} + if (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET) + { + TimingDelay = 0x00; + } + } + if (TimingDelay == 0x00) + { + /* Turn off LEDs available on STM32F4-Discovery ------------------------*/ + STM_EVAL_LEDOff(LED4); + STM_EVAL_LEDOff(LED3); + STM_EVAL_LEDOff(LED5); + STM_EVAL_LEDOff(LED6); + + /* Waiting User Button is released */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET) + {} + + /* Unlocks the FLASH control register access */ + FLASH_Unlock(); + + /* Move discovery kit to detect negative and positive acceleration values + on X, Y and Z axis */ + Accelerometer_MEMS_Test(); + + /* USB Hardware connection */ + USB_Test(); + + /* Audio Hardware connection */ + Audio_Test(); + + /* Microphone MEMS Hardware connection */ + Microphone_MEMS_Test(); + + /* Write PASS code at last word in the flash memory */ + FLASH_ProgramWord(TESTRESULT_ADDRESS, ALLTEST_PASS); + + while(1) + { + /* Toggle Green LED: signaling the End of the Test program */ + STM_EVAL_LEDToggle(LED4); + Delay(10); + } + } + else + { + Demo_Exec(); + } + } + else + { + Demo_Exec(); + } +} + +/** + * @brief Execute the demo application. + * @param None + * @retval None + */ +static void Demo_Exec(void) +{ + RCC_ClocksTypeDef RCC_Clocks; + uint8_t togglecounter = 0x00; + + while(1) + { + DemoEnterCondition = 0x00; + + /* Reset UserButton_Pressed variable */ + UserButtonPressed = 0x00; + + /* Initialize LEDs to be managed by GPIO */ + STM_EVAL_LEDInit(LED4); + STM_EVAL_LEDInit(LED3); + STM_EVAL_LEDInit(LED5); + STM_EVAL_LEDInit(LED6); + + /* SysTick end of count event each 10ms */ + RCC_GetClocksFreq(&RCC_Clocks); + SysTick_Config(RCC_Clocks.HCLK_Frequency / 100); + + /* Turn OFF all LEDs */ + STM_EVAL_LEDOff(LED4); + STM_EVAL_LEDOff(LED3); + STM_EVAL_LEDOff(LED5); + STM_EVAL_LEDOff(LED6); + + /* Waiting User Button is pressed */ + while (UserButtonPressed == 0x00) + { + /* Toggle LED4 */ + STM_EVAL_LEDToggle(LED4); + Delay(10); + /* Toggle LED4 */ + STM_EVAL_LEDToggle(LED3); + Delay(10); + /* Toggle LED4 */ + STM_EVAL_LEDToggle(LED5); + Delay(10); + /* Toggle LED4 */ + STM_EVAL_LEDToggle(LED6); + Delay(10); + togglecounter ++; + if (togglecounter == 0x10) + { + togglecounter = 0x00; + while (togglecounter < 0x10) + { + STM_EVAL_LEDToggle(LED4); + STM_EVAL_LEDToggle(LED3); + STM_EVAL_LEDToggle(LED5); + STM_EVAL_LEDToggle(LED6); + Delay(10); + togglecounter ++; + } + togglecounter = 0x00; + } + } + + /* Waiting User Button is Released */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET) + {} + UserButtonPressed = 0x00; + + /* TIM4 channels configuration */ + TIM4_Config(); + + /* Disable all Timer4 channels */ + TIM_CCxCmd(TIM4, TIM_Channel_1, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_2, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_3, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_4, DISABLE); + + /* MEMS configuration */ + LIS302DL_InitStruct.Power_Mode = LIS302DL_LOWPOWERMODE_ACTIVE; + LIS302DL_InitStruct.Output_DataRate = LIS302DL_DATARATE_100; + LIS302DL_InitStruct.Axes_Enable = LIS302DL_XYZ_ENABLE; + LIS302DL_InitStruct.Full_Scale = LIS302DL_FULLSCALE_2_3; + LIS302DL_InitStruct.Self_Test = LIS302DL_SELFTEST_NORMAL; + LIS302DL_Init(&LIS302DL_InitStruct); + + /* Required delay for the MEMS Accelerometre: Turn-on time = 3/Output data Rate + = 3/100 = 30ms */ + Delay(30); + + DemoEnterCondition = 0x01; + /* MEMS High Pass Filter configuration */ + LIS302DL_FilterStruct.HighPassFilter_Data_Selection = LIS302DL_FILTEREDDATASELECTION_OUTPUTREGISTER; + LIS302DL_FilterStruct.HighPassFilter_CutOff_Frequency = LIS302DL_HIGHPASSFILTER_LEVEL_1; + LIS302DL_FilterStruct.HighPassFilter_Interrupt = LIS302DL_HIGHPASSFILTERINTERRUPT_1_2; + LIS302DL_FilterConfig(&LIS302DL_FilterStruct); + + LIS302DL_Read(Buffer, LIS302DL_OUT_X_ADDR, 6); + X_Offset = Buffer[0]; + Y_Offset = Buffer[2]; + Z_Offset = Buffer[4]; + + /* USB configuration */ + Demo_USBConfig(); + + /* Waiting User Button is pressed */ + while (UserButtonPressed == 0x00) + {} + + /* Waiting User Button is Released */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET) + {} + + /* Disable SPI1 used to drive the MEMS accelerometre */ + SPI_Cmd(LIS302DL_SPI, DISABLE); + + /* Disconnect the USB device */ + DCD_DevDisconnect(&USB_OTG_dev); + USB_OTG_StopDevice(&USB_OTG_dev); + } +} + +/** + * @brief Initializes the USB for the demonstration application. + * @param None + * @retval None + */ +static uint32_t Demo_USBConfig(void) +{ + USBD_Init(&USB_OTG_dev, + USB_OTG_FS_CORE_ID, + &USR_desc, + &USBD_HID_cb, + &USR_cb); + + return 0; +} + +/** + * @brief Configures the TIM Peripheral. + * @param None + * @retval None + */ +static void TIM4_Config(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + TIM_OCInitTypeDef TIM_OCInitStructure; + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + + /* --------------------------- System Clocks Configuration -----------------*/ + /* TIM4 clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); + + /* GPIOD clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + /*-------------------------- GPIO Configuration ----------------------------*/ + /* GPIOD Configuration: Pins 12, 13, 14 and 15 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + /* Connect TIM4 pins to AF2 */ + GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4); + + /* ----------------------------------------------------------------------- + TIM4 Configuration: Output Compare Timing Mode: + + In this example TIM4 input clock (TIM4CLK) is set to 2 * APB1 clock (PCLK1), + since APB1 prescaler is different from 1 (APB1 Prescaler = 4, see system_stm32f4xx.c file). + TIM4CLK = 2 * PCLK1 + PCLK1 = HCLK / 4 + => TIM4CLK = 2*(HCLK / 4) = HCLK/2 = SystemCoreClock/2 + + To get TIM4 counter clock at 2 KHz, the prescaler is computed as follows: + Prescaler = (TIM4CLK / TIM1 counter clock) - 1 + Prescaler = (168 MHz/(2 * 2 KHz)) - 1 = 41999 + + To get TIM4 output clock at 1 Hz, the period (ARR)) is computed as follows: + ARR = (TIM4 counter clock / TIM4 output clock) - 1 + = 1999 + + TIM4 Channel1 duty cycle = (TIM4_CCR1/ TIM4_ARR)* 100 = 50% + TIM4 Channel2 duty cycle = (TIM4_CCR2/ TIM4_ARR)* 100 = 50% + TIM4 Channel3 duty cycle = (TIM4_CCR3/ TIM4_ARR)* 100 = 50% + TIM4 Channel4 duty cycle = (TIM4_CCR4/ TIM4_ARR)* 100 = 50% + + ==> TIM4_CCRx = TIM4_ARR/2 = 1000 (where x = 1, 2, 3 and 4). + + Note: + SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file. + Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate() + function to update SystemCoreClock variable value. Otherwise, any configuration + based on this variable will be incorrect. + ----------------------------------------------------------------------- */ + + + /* Compute the prescaler value */ + PrescalerValue = (uint16_t) ((SystemCoreClock /2) / 2000) - 1; + + /* Time base configuration */ + TIM_TimeBaseStructure.TIM_Period = TIM_ARR; + TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); + + /* Enable TIM4 Preload register on ARR */ + TIM_ARRPreloadConfig(TIM4, ENABLE); + + /* TIM PWM1 Mode configuration: Channel */ + TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; + TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; + TIM_OCInitStructure.TIM_Pulse = TIM_CCR; + TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; + + /* Output Compare PWM1 Mode configuration: Channel1 */ + TIM_OC1Init(TIM4, &TIM_OCInitStructure); + TIM_CCxCmd(TIM4, TIM_Channel_1, DISABLE); + + TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable); + + /* Output Compare PWM1 Mode configuration: Channel2 */ + TIM_OC2Init(TIM4, &TIM_OCInitStructure); + TIM_CCxCmd(TIM4, TIM_Channel_2, DISABLE); + + TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable); + + /* Output Compare PWM1 Mode configuration: Channel3 */ + TIM_OC3Init(TIM4, &TIM_OCInitStructure); + TIM_CCxCmd(TIM4, TIM_Channel_3, DISABLE); + + TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); + + /* Output Compare PWM1 Mode configuration: Channel4 */ + TIM_OC4Init(TIM4, &TIM_OCInitStructure); + TIM_CCxCmd(TIM4, TIM_Channel_4, DISABLE); + + TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); + + /* TIM4 enable counter */ + TIM_Cmd(TIM4, ENABLE); +} + +/** + * @brief Inserts a delay time. + * @param nTime: specifies the delay time length, in 10 ms. + * @retval None + */ +void Delay(__IO uint32_t nTime) +{ + TimingDelay = nTime; + + while(TimingDelay != 0); +} + +/** + * @brief Decrements the TimingDelay variable. + * @param None + * @retval None + */ +void TimingDelay_Decrement(void) +{ + if (TimingDelay != 0x00) + { + TimingDelay--; + } +} + +/** + * @brief This function handles the test program fail. + * @param None + * @retval None + */ +void Fail_Handler(void) +{ + /* Erase last sector */ + FLASH_EraseSector(FLASH_Sector_11, VoltageRange_3); + /* Write FAIL code at last word in the flash memory */ + FLASH_ProgramWord(TESTRESULT_ADDRESS, ALLTEST_FAIL); + + while(1) + { + /* Toggle Red LED */ + STM_EVAL_LEDToggle(LED5); + Delay(5); + } +} + +/** + * @brief MEMS accelerometre management of the timeout situation. + * @param None. + * @retval None. + */ +uint32_t LIS302DL_TIMEOUT_UserCallback(void) +{ + /* MEMS Accelerometer Timeout error occured during Test program execution */ + if (DemoEnterCondition == 0x00) + { + /* Timeout error occured for SPI TXE/RXNE flags waiting loops.*/ + Fail_Handler(); + } + /* MEMS Accelerometer Timeout error occured during Demo execution */ + else + { + while (1) + { + } + } + return 0; +} + +#ifdef USE_FULL_ASSERT + +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t* file, uint32_t line) +{ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + + /* Infinite loop */ + while (1) + { + } +} +#endif + +/** + * @} + */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/main.h b/example/stm32f4/Projects/discovery_demo/main.h new file mode 100644 index 0000000..cc19bb4 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/main.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file main.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief Header for main.c module + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4_DISCOVERY_DEMO_H +#define __STM32F4_DISCOVERY_DEMO_H + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4_discovery.h" +#include "stm32f4_discovery_audio_codec.h" +#include "stm32f4_discovery_lis302dl.h" +#include "selftest.h" +#include + + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* TIM2 Autoreload and Capture Compare register values */ +#define TIM_ARR (uint16_t)1999 +#define TIM_CCR (uint16_t)1000 + +/* MEMS Microphone SPI Interface */ +#define SPI_SCK_PIN GPIO_Pin_10 +#define SPI_SCK_GPIO_PORT GPIOB +#define SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB +#define SPI_SCK_SOURCE GPIO_PinSource10 +#define SPI_SCK_AF GPIO_AF_SPI2 + +#define SPI_MOSI_PIN GPIO_Pin_3 +#define SPI_MOSI_GPIO_PORT GPIOC +#define SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOC +#define SPI_MOSI_SOURCE GPIO_PinSource3 +#define SPI_MOSI_AF GPIO_AF_SPI2 + +/* Exported macro ------------------------------------------------------------*/ +#define ABS(x) (x < 0) ? (-x) : x +#define MAX(a,b) (a < b) ? (b) : a +/* Exported functions ------------------------------------------------------- */ +void TimingDelay_Decrement(void); +void Delay(__IO uint32_t nTime); +void Fail_Handler(void); +#endif /* __STM32F4_DISCOVERY_DEMO_H */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/selftest.c b/example/stm32f4/Projects/discovery_demo/selftest.c new file mode 100644 index 0000000..7183ffa --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/selftest.c @@ -0,0 +1,808 @@ +/** + ****************************************************************************** + * @file selftest.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file provides the hardware tests + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ */ + +/* Includes ------------------------------------------------------------------*/ +#include "selftest.h" + +//Library config for this project!!!!!!!!!!! +#include "stm32f4xx_conf.h" + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define MEMS_PASSCONDITION 15 +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Init Structure definition */ +RCC_ClocksTypeDef RCC_Clocks; +ADC_InitTypeDef ADC_InitStructure; +ADC_CommonInitTypeDef ADC_CommonInitStructure; + +__IO uint16_t ConvData1, ConvData2; +__IO uint16_t counter0 = 0, counter1 = 0, Idx = 0; +uint8_t ADC_Channel[2] = {ADC_Channel_2, ADC_Channel_3}; +uint8_t DACTest = 0; +uint8_t GPIO_Pin [2] = {GPIO_Pin_2, GPIO_Pin_3}; + +uint16_t count = 0, count1 = 24, Left_Right = 0; +const int16_t sinebuf[48] = {0, 4276, 8480, 12539, 16383, 19947, 23169, 25995, + 28377, 30272, 31650, 32486, 32767, 32486, 31650, 30272, + 28377, 25995, 23169, 19947, 16383, 12539, 8480, 4276, + 0, -4276, -8480, -12539, -16383, -19947, -23169, -25995, + -28377, -30272, -31650, -32486, -32767, -32486, -31650, -30272, + -28377, -25995, -23169, -19947, -16383, -12539, -8480, -4276 + }; +extern __IO uint32_t TimingDelay; + +extern LIS302DL_InitTypeDef LIS302DL_InitStruct; +extern LIS302DL_FilterConfigTypeDef LIS302DL_FilterStruct; + +extern __IO int8_t X_Offset, Y_Offset, Z_Offset; +extern uint8_t Buffer[6]; +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/** + * @brief Test MEMS Hardware. + * The main objectif of this test is to check the hardware connection of the + * MEMS peripheral. + * @param None + * @retval None + */ +void Accelerometer_MEMS_Test(void) +{ + uint8_t temp, memsteststatus = 0x00; + uint8_t xdata, ydata = 0; + + /* MEMS configuration ------------------------------------------------------*/ + /* Set configuration of LIS302DL*/ + LIS302DL_InitStruct.Power_Mode = LIS302DL_LOWPOWERMODE_ACTIVE; + LIS302DL_InitStruct.Output_DataRate = LIS302DL_DATARATE_100; + LIS302DL_InitStruct.Axes_Enable = LIS302DL_X_ENABLE | LIS302DL_Y_ENABLE; + LIS302DL_InitStruct.Full_Scale = LIS302DL_FULLSCALE_2_3; + LIS302DL_InitStruct.Self_Test = LIS302DL_SELFTEST_NORMAL; + LIS302DL_Init(&LIS302DL_InitStruct); + + /* Set configuration of Internal High Pass Filter of LIS302DL*/ + LIS302DL_FilterStruct.HighPassFilter_Data_Selection = LIS302DL_FILTEREDDATASELECTION_OUTPUTREGISTER; + LIS302DL_FilterStruct.HighPassFilter_CutOff_Frequency = LIS302DL_HIGHPASSFILTER_LEVEL_1; + LIS302DL_FilterStruct.HighPassFilter_Interrupt = LIS302DL_HIGHPASSFILTERINTERRUPT_1_2; + LIS302DL_FilterConfig(&LIS302DL_FilterStruct); + + /* Required delay for the MEMS Accelerometre: Turn-on time = 3/Output data Rate + = 3/100 = 30ms */ + Delay(30); + + /* Read WHO_AM_I register */ + LIS302DL_Read(&temp, LIS302DL_WHO_AM_I_ADDR, 1); + + /* Check device identification register, this register should contains + the device identifier that for LIS302DL is set to 0x3B */ + if (temp != 0x3B) + { + Fail_Handler(); + } + + TimingDelay = 500; + /* Wait until detecting all MEMS direction or timeout */ + while((memsteststatus == 0x00)&&(TimingDelay != 0x00)) + { + LIS302DL_Read(Buffer, LIS302DL_OUT_X_ADDR, 4); + xdata = ABS((int8_t)(Buffer[0])); + ydata = ABS((int8_t)(Buffer[2])); + /* Check test PASS condition */ + if ((xdata > MEMS_PASSCONDITION) || (ydata > MEMS_PASSCONDITION)) + { + /* MEMS Test PASS */ + memsteststatus = 0x01; + } + } + + /* MEMS test status: PASS */ + if(memsteststatus != 0x00) + { + /* Turn Green LED ON: signaling MEMS Test PASS */ + STM_EVAL_LEDOn(LED4); + + /* Waiting User Button is pressed */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET) + {} + + /* Waiting User Button is Released */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET) + {} + + /* Turn Green LED OFF: signaling the end of MEMS Test and switching to + the next Sub Test */ + STM_EVAL_LEDOff(LED4); + } + /* MEMS test status: Timeout occurs */ + else + { + Fail_Handler(); + } +} + +/** + * @brief Test USB Hardware. + * The main objectif of this test is to check the hardware connection of the + * Audio and USB peripheral. + * @param None + * @retval None + */ +void USB_Test(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /******************************** USB Test **********************************/ + + /*----------------- Part1: without cables connected ------------------------*/ + + /* GPIOA, GPIOC and GPIOD clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | \ + RCC_AHB1Periph_GPIOD, ENABLE); + + /* GPIOD Configuration: Pins 5 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOD, &GPIO_InitStructure); + + /* Turn LED8 ON using PD5 */ + GPIO_ResetBits(GPIOD, GPIO_Pin_5); + + /* GPIOC Configuration: Pin 0 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 9 in input pull-up */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Turn LED7 ON using PC0 (5v) */ + GPIO_ResetBits(GPIOC, GPIO_Pin_0); + + /* Waiting delay 10ms */ + Delay(1); + + if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 10 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check the ID level without cable connected */ + if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) == Bit_RESET) + { + Fail_Handler(); + } + + /* Turn LED7 OFF using PC0 */ + GPIO_SetBits(GPIOC, GPIO_Pin_0); + + /* GPIOA Configuration: Pins 11, 12 in input pull-up */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 9 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_ResetBits(GPIOA, GPIO_Pin_9); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA11 and PA12 level without cable connected */ + if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET) || \ + (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET)) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 12 in input pull-up */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 11 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_ResetBits(GPIOA, GPIO_Pin_11); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA12 level without cable connected */ + if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 11 in input pull-up */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 12 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_ResetBits(GPIOA, GPIO_Pin_12); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA12 level without cable connected */ + if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 9 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Turn LED7 ON using PA9 */ + GPIO_SetBits(GPIOA, GPIO_Pin_9); + + /* Turn Green LED ON: signaling Audio USB Test part1 PASS */ + STM_EVAL_LEDOn(LED4); + + /* Waiting User Button is pressed */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET) + {} + + /* Waiting User Button is Released */ + while (STM_EVAL_PBGetState(BUTTON_USER) != Bit_RESET) + {} + + /* Turn Green LED OFF: signaling the end of Audio USB Test part1 and switching to + the part2 */ + STM_EVAL_LEDOff(LED4); + + /* Turn LED7 OFF using PA9 */ + GPIO_ResetBits(GPIOA, GPIO_Pin_9); + + /* Turn LED8 OFF using PD5 */ + GPIO_SetBits(GPIOD, GPIO_Pin_5); + + /*--------------- Part2: with Audio USB cables connected ------------------*/ + + /*********************************** USB Test *******************************/ + /* Check the ID level with cable connected */ + if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) != Bit_RESET) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 11, 12 in input pull-down */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 9 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_SetBits(GPIOA, GPIO_Pin_9); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA11 and PA12 level with cable connected */ + if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET) || \ + (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET)) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 9, 12 in input pull-down */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 11 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_SetBits(GPIOA, GPIO_Pin_11); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA9 and PA12 level with cable connected */ + if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET)|| \ + (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == Bit_RESET)) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 9, 11 in input pull-down */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 12 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_SetBits(GPIOA, GPIO_Pin_12); + + /* Waiting delay 10ms */ + Delay(1); + + /* Check PA9 and PA12 level with cable connected */ + if ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9) == Bit_RESET)|| \ + (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == Bit_RESET)) + { + Fail_Handler(); + } + + /* GPIOA Configuration: Pins 11, 12 in input pull-down */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOA Configuration: Pin 9 in output push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Turn LED7 OFF using PA9 */ + GPIO_ResetBits(GPIOA, GPIO_Pin_9); +} + +/** + * @brief Test Audio Hardware. + * The main objectif of this test is to check the hardware connection of the + * Audio peripheral. + * @param None + * @retval None + */ +void Audio_Test(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + uint8_t audioteststatus = 0x00; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); + + /* Set the current audio interface: I2S or DAC */ + EVAL_AUDIO_SetAudioInterface(AUDIO_INTERFACE_I2S); + + /* Initialize the Audio codec and all related peripherals (I2S, I2C, IOs...) */ + if (EVAL_AUDIO_Init(OUTPUT_DEVICE_HEADPHONE, 87, I2S_AudioFreq_48k) !=0) + { + Fail_Handler(); + } + /* I2S code to be exectued under the I2S interrupt */ + DACTest = 0; + + /* ADC Common Init */ + ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; + ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8; + ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; + ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; + ADC_CommonInit(&ADC_CommonInitStructure); + + /* ADC peripherals Init */ + ADC_StructInit(&ADC_InitStructure); + ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; + ADC_InitStructure.ADC_ScanConvMode = DISABLE; + ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; + ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; + ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; + ADC_InitStructure.ADC_NbrOfConversion = 1; + ADC_Init(ADC1, &ADC_InitStructure); + + ADC_Init(ADC2, &ADC_InitStructure); + + /* Configure ADC Channels pin as analog input */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + counter1 = 0; + counter0 = 0; + audioteststatus = 0; + /* ADCperipheral[PerIdx] Regular Channel Config */ + ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_56Cycles); + /* ADCperipheral[PerIdx] Regular Channel Config */ + ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 1, ADC_SampleTime_56Cycles); + /* Enable ADC1 */ + ADC_Cmd(ADC1, ENABLE); + ADC_Cmd(ADC2, ENABLE); + + TimingDelay = 500; + /* Wait until detecting 500 data*/ + while((audioteststatus == 0)&&(TimingDelay != 0)) + { + ADC_SoftwareStartConv(ADC1); + while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); + ConvData1 = ADC_GetConversionValue(ADC1); + + ADC_SoftwareStartConv(ADC2); + while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET); + ConvData2 = ADC_GetConversionValue(ADC2); + + /* 1.75V equals to 150 */ + if ((ConvData1 > 150) && (ConvData2 < 10) && (counter1 != 500)) + { + counter1 ++; + } + if ((ConvData1 < 10) && (ConvData2 > 150) && (counter0 != 500)) + { + counter0 ++; + } + if((counter1 == 500) && (counter0 == 500)) + { + audioteststatus = 1; + } + } + + /* Disable ADC Peripherals */ + ADC_Cmd(ADC1, DISABLE); + ADC_Cmd(ADC2, DISABLE); + + /* Audio test status: FAIL */ + if(audioteststatus == 0) + { + Fail_Handler(); + } + + EVAL_AUDIO_DeInit(); + EVAL_AUDIO_SetAudioInterface(AUDIO_INTERFACE_DAC); + /* Initialize the Audio codec and all related peripherals (I2S, I2C, IOs...) */ + if (EVAL_AUDIO_Init(OUTPUT_DEVICE_HEADPHONE, 100, I2S_AudioFreq_48k) !=0) + { + Fail_Handler(); + } + + /* DAC code to be exectued under the I2S interrupt */ + DACTest = 1; + counter1 = 0; + counter0 = 0; + audioteststatus = 0; + + /* Enable ADC1 */ + ADC_Cmd(ADC1, ENABLE); + ADC_Cmd(ADC2, ENABLE); + + TimingDelay = 500; + /* Wait until detecting 50 data*/ + while((audioteststatus == 0)&&(TimingDelay != 0)) + { + + ADC_SoftwareStartConv(ADC1); + while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); + + ConvData1 = ADC_GetConversionValue(ADC1); + + ADC_SoftwareStartConv(ADC2); + while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET); + + ConvData2 = ADC_GetConversionValue(ADC2); + + /* 2.0V equals to 170 */ + if ((ConvData1 > 170) && (ConvData2 > 170) &&(counter1 != 500)) + { + counter1 ++; + } + if ((ConvData1 < 10) && (ConvData2 < 10) && (counter0 != 500)) + { + counter0 ++; + } + if((counter1 == 500) && (counter0 == 500)) + { + audioteststatus = 1; + } + } + + /* Audio test status: FAIL */ + if(audioteststatus == 0x00) + { + Fail_Handler(); + } + + /* Turn Green LED ON: signaling Audio USB Test part2 PASS */ + STM_EVAL_LEDOn(LED4); + + /* Waiting User_Button pressed */ + while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET) + {} + + /* Turn Green LED OFF: signaling the end of Audio USB Test part2 */ + STM_EVAL_LEDOff(LED4); +} + +/** + * @brief Test Micophone MEMS Hardware. + * The main objectif of this test is to check the hardware connection of the + * Microphone MEMS peripheral. + * @param None + * @retval None + */ +void Microphone_MEMS_Test(void) +{ + uint16_t data = 0x00; + uint8_t index = 0x00; + I2S_InitTypeDef I2S_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable the SPI clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + + /* Enable GPIO clocks */ + RCC_AHB1PeriphClockCmd(SPI_SCK_GPIO_CLK | SPI_MOSI_GPIO_CLK, ENABLE); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; + + /* SPI SCK pin configuration */ + GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN; + GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStructure); + + /* Connect SPI pins to AF5 */ + GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_SOURCE, SPI_SCK_AF); + + /* SPI MOSI pin configuration */ + GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN; + GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); + + GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF); + + /* I2S configuration -------------------------------------------------------*/ + SPI_I2S_DeInit(SPI2); + I2S_InitStructure.I2S_AudioFreq = 64000; + I2S_InitStructure.I2S_Standard = I2S_Standard_MSB; + I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b; + I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; + I2S_InitStructure.I2S_Mode = I2S_Mode_MasterRx; + I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable; + /* Initialize the I2S peripheral with the structure above */ + I2S_Init(SPI2, &I2S_InitStructure); + + /* Enable the I2S peripheral */ + I2S_Cmd(SPI2, ENABLE); + + /* Waiting until MEMS microphone ready : Wake-up Time */ + Delay(10); + + TimingDelay = 500; + /* Wait until detect the click on the MEMS microphone or TimeOut delay*/ + while((index < 30) && (TimingDelay != 0x00)) + { + /* Waiting RXNE Flag or TimeOut delay */ + while((SPI_I2S_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET)&& (TimingDelay != 0x00)) + {} + data = SPI_I2S_ReceiveData(SPI2); + if (data == 0xFFFF) + { + index++; + } + } + + /* MEMS microphone test status: Timeout occurs */ + if(index != 30) + { + Fail_Handler(); + } +} + +/*-------------------------------- + Callbacks implementation: + the callbacks prototypes are defined in the stm324xg_eval_audio_codec.h file + and their implementation should be done in the user code if they are needed. + Below some examples of callback implementations. + --------------------------------------------------------*/ +/** + * @brief Calculates the remaining file size and new position of the pointer. + * @param None + * @retval None + */ +void EVAL_AUDIO_TransferComplete_CallBack(uint32_t pBuffer, uint32_t Size) +{ + /* Calculate the remaining audio data in the file and the new size + for the DMA transfer. If the Audio files size is less than the DMA max + data transfer size, so there is no calculation to be done, just restart + from the beginning of the file ... */ + /* Check if the end of file has been reached */ + +} + +/** + * @brief Manages the DMA Half Transfer complete interrupt. + * @param None + * @retval None + */ +void EVAL_AUDIO_HalfTransfer_CallBack(uint32_t pBuffer, uint32_t Size) +{ +#ifdef AUDIO_MAL_MODE_CIRCULAR + + /* Display message on the LCD screen */ + LCD_DisplayStringLine(Line8, " 1/2 Buffer Reached "); + +#endif /* AUDIO_MAL_MODE_CIRCULAR */ + + /* Generally this interrupt routine is used to load the buffer when + a streaming scheme is used: When first Half buffer is already transferred load + the new data to the first half of buffer while DMA is transferring data from + the second half. And when Transfer complete occurs, load the second half of + the buffer while the DMA is transferring from the first half ... */ + /* + ........... + */ +} +/** + * @brief Get next data sample callback + * @param None + * @retval Next data sample to be sent + */ +uint16_t EVAL_AUDIO_GetSampleCallBack(void) +{ + uint16_t data = 0; + + if (DACTest == 0) + { + if (Left_Right==0) + { + /* Get the next sample to be sent */ + data = sinebuf[count++]; + + if (count == 48) + { + count = 0x00; + } + Left_Right = 1; + } + else + { + /* Get the next sample to be sent */ + data = sinebuf[count1++]; + + if (count1 == 48) + { + count1 = 0x00; + } + Left_Right = 0; + } + } + else + { + /* Get the next sample to be sent */ + data = 32768 + sinebuf[count++]; + + if (count == 48) + { + count = 0x00; + } + } + return data; +} + + +/** + * @brief Manages the DMA FIFO error interrupt. + * @param None + * @retval None + */ +void EVAL_AUDIO_Error_CallBack(void* pData) +{ + /* Stop the program with an infinite loop */ + while (1) + {} + + /* could also generate a system reset to recover from the error */ + /* .... */ +} + +#ifndef USE_DEFAULT_TIMEOUT_CALLBACK +/** + * @brief Basic management of the timeout situation. + * @param None. + * @retval None. + */ +uint32_t Codec_TIMEOUT_UserCallback(void) +{ + /* Block communication and all processes */ + while (1) + { + } +} +#endif /* USE_DEFAULT_TIMEOUT_CALLBACK */ +/*----------------------------------------------------------------------------*/ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/selftest.h b/example/stm32f4/Projects/discovery_demo/selftest.h new file mode 100644 index 0000000..feef3de --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/selftest.h @@ -0,0 +1,41 @@ +/** + ****************************************************************************** + * @file selftest.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief Header for selftest.c module + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SELFTEST_H +#define __SELFTEST_H + +/* Includes ------------------------------------------------------------------*/ +#include +#include "main.h" +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void Audio_Test(void); +void Accelerometer_MEMS_Test(void); +void USB_Test(void); +void Microphone_MEMS_Test(void); + +#endif /* __SELFTEST_H */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/startup_stm32f4xx.s b/example/stm32f4/Projects/discovery_demo/startup_stm32f4xx.s new file mode 100644 index 0000000..ce5360f --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/startup_stm32f4xx.s @@ -0,0 +1,509 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for RIDE7 toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system and the external SRAM mounted on + * STM324xG-EVAL board to be used as data memory (optional, + * to be enabled by user) + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M3. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word CRYP_IRQHandler /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak CRYP_IRQHandler + .thumb_set CRYP_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/stm32_flash.ld b/example/stm32f4/Projects/discovery_demo/stm32_flash.ld new file mode 100644 index 0000000..ee842a7 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/stm32_flash.ld @@ -0,0 +1,170 @@ +/* +***************************************************************************** +** +** File : stm32_flash.ld +** +** Abstract : Linker script for STM32F207IG Device with +** 1024KByte FLASH, 112KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Environment : Atollic TrueSTUDIO(R) +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +** (c)Copyright Atollic AB. +** You may use this file as-is or modify it according to the needs of your +** project. Distribution of this file (unmodified or modified) is not +** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the +** rights to distribute the assembled, compiled & linked contents of this +** file as part of an application binary file, provided that it is built +** using the Atollic TrueSTUDIO(R) toolchain. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x2001c000; /* end of 112K RAM */ + +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K + MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array*)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = .; + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM + + /* MEMORY_bank1 section, code must be located here explicitly */ + /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */ + .memory_b1_text : + { + *(.mb1text) /* .mb1text sections (code) */ + *(.mb1text*) /* .mb1text* sections (code) */ + *(.mb1rodata) /* read-only data (constants) */ + *(.mb1rodata*) + } >MEMORY_B1 + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/example/stm32f4/Projects/discovery_demo/stm32f4xx_conf.h b/example/stm32f4/Projects/discovery_demo/stm32f4xx_conf.h new file mode 100644 index 0000000..74447a8 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/stm32f4xx_conf.h @@ -0,0 +1,94 @@ +/** + ****************************************************************************** + * @file stm32f4xx_conf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief Library configuration file. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_CONF_H +#define __STM32F4xx_CONF_H + +#if defined (HSE_VALUE) +/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */ + #undef HSE_VALUE + #define HSE_VALUE ((uint32_t)8000000) +#endif /* HSE_VALUE */ + +/* Includes ------------------------------------------------------------------*/ +/* Uncomment the line below to enable peripheral header file inclusion */ +#include "stm32f4xx_adc.h" +#include "stm32f4xx_can.h" +#include "stm32f4xx_crc.h" +#include "stm32f4xx_cryp.h" +#include "stm32f4xx_dac.h" +#include "stm32f4xx_dbgmcu.h" +#include "stm32f4xx_dcmi.h" +#include "stm32f4xx_dma.h" +#include "stm32f4xx_exti.h" +#include "stm32f4xx_flash.h" +#include "stm32f4xx_fsmc.h" +#include "stm32f4xx_hash.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_i2c.h" +#include "stm32f4xx_iwdg.h" +#include "stm32f4xx_pwr.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_rng.h" +#include "stm32f4xx_rtc.h" +#include "stm32f4xx_sdio.h" +#include "stm32f4xx_spi.h" +#include "stm32f4xx_syscfg.h" +#include "stm32f4xx_tim.h" +#include "stm32f4xx_usart.h" +#include "stm32f4xx_wwdg.h" +#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* If an external clock source is used, then the value of the following define + should be set to the value of the external clock source, else, if no external + clock is used, keep this define commented */ +/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */ + + +/* Uncomment the line below to expanse the "assert_param" macro in the + Standard Peripheral Library drivers code */ +/* #define USE_FULL_ASSERT 1 */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT + +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#endif /* __STM32F4xx_CONF_H */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.c b/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.c new file mode 100644 index 0000000..cee2c24 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.c @@ -0,0 +1,320 @@ +/** + ****************************************************************************** + * @file stm32f4xx_it.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief Main Interrupt Service Routines. + * This file provides all exceptions handler and peripherals interrupt + * service routine. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_it.h" +#include "main.h" +#include "usb_core.h" +#include "usbd_core.h" +#include "stm32f4_discovery.h" +#include "usbd_hid_core.h" + +//Library config for this project!!!!!!!!!!! +#include "stm32f4xx_conf.h" + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define CURSOR_STEP 7 + +extern uint8_t Buffer[6]; +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +extern __IO uint8_t DemoEnterCondition; +uint8_t Counter = 0x00; +extern int8_t X_Offset; +extern int8_t Y_Offset; +extern __IO uint8_t UserButtonPressed; +__IO uint8_t TempAcceleration = 0; +/* Private function prototypes -----------------------------------------------*/ +extern USB_OTG_CORE_HANDLE USB_OTG_dev; +static uint8_t *USBD_HID_GetPos (void); +extern uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev); + +/******************************************************************************/ +/* Cortex-M3 Processor Exceptions Handlers */ +/******************************************************************************/ + +/** + * @brief This function handles NMI exception. + * @param None + * @retval None + */ +void NMI_Handler(void) +{ +} + +/** + * @brief This function handles Hard Fault exception. + * @param None + * @retval None + */ +void HardFault_Handler(void) +{ + /* Go to infinite loop when Hard Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Memory Manage exception. + * @param None + * @retval None + */ +void MemManage_Handler(void) +{ + /* Go to infinite loop when Memory Manage exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Bus Fault exception. + * @param None + * @retval None + */ +void BusFault_Handler(void) +{ + /* Go to infinite loop when Bus Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Usage Fault exception. + * @param None + * @retval None + */ +void UsageFault_Handler(void) +{ + /* Go to infinite loop when Usage Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles SVCall exception. + * @param None + * @retval None + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Debug Monitor exception. + * @param None + * @retval None + */ +void DebugMon_Handler(void) +{ +} + +/** + * @brief This function handles PendSVC exception. + * @param None + * @retval None + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles SysTick Handler. + * @param None + * @retval None + */ +void SysTick_Handler(void) +{ + uint8_t *buf; + uint8_t temp1, temp2 = 0x00; + + if (DemoEnterCondition == 0x00) + { + TimingDelay_Decrement(); + } + else + { + buf = USBD_HID_GetPos(); + if((buf[1] != 0) ||(buf[2] != 0)) + { + USBD_HID_SendReport (&USB_OTG_dev, + buf, + 4); + } + Counter ++; + if (Counter == 10) + { + Buffer[0] = 0; + Buffer[2] = 0; + /* Disable All TIM4 Capture Compare Channels */ + TIM_CCxCmd(TIM4, TIM_Channel_1, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_2, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_3, DISABLE); + TIM_CCxCmd(TIM4, TIM_Channel_4, DISABLE); + + LIS302DL_Read(Buffer, LIS302DL_OUT_X_ADDR, 6); + /* Remove the offsets values from data */ + Buffer[0] -= X_Offset; + Buffer[2] -= Y_Offset; + /* Update autoreload and capture compare registers value*/ + temp1 = ABS((int8_t)(Buffer[0])); + temp2 = ABS((int8_t)(Buffer[2])); + TempAcceleration = MAX(temp1, temp2); + + if(TempAcceleration != 0) + { + if ((int8_t)Buffer[0] < -2) + { + /* Enable TIM4 Capture Compare Channel 4 */ + TIM_CCxCmd(TIM4, TIM_Channel_4, ENABLE); + /* Sets the TIM4 Capture Compare4 Register value */ + TIM_SetCompare4(TIM4, TIM_CCR/TempAcceleration); + } + if ((int8_t)Buffer[0] > 2) + { + /* Enable TIM4 Capture Compare Channel 2 */ + TIM_CCxCmd(TIM4, TIM_Channel_2, ENABLE); + /* Sets the TIM4 Capture Compare2 Register value */ + TIM_SetCompare2(TIM4, TIM_CCR/TempAcceleration); + } + if ((int8_t)Buffer[2] > 2) + { + /* Enable TIM4 Capture Compare Channel 1 */ + TIM_CCxCmd(TIM4, TIM_Channel_1, ENABLE); + /* Sets the TIM4 Capture Compare1 Register value */ + TIM_SetCompare1(TIM4, TIM_CCR/TempAcceleration); + } + if ((int8_t)Buffer[2] < -2) + { + /* Enable TIM4 Capture Compare Channel 3 */ + TIM_CCxCmd(TIM4, TIM_Channel_3, ENABLE); + /* Sets the TIM4 Capture Compare3 Register value */ + TIM_SetCompare3(TIM4, TIM_CCR/TempAcceleration); + } + /* Time base configuration */ + TIM_SetAutoreload(TIM4, TIM_ARR/TempAcceleration); + } + Counter = 0x00; + } + } + +} + +/******************************************************************************/ +/* STM32Fxxx Peripherals Interrupt Handlers */ +/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ +/* available peripheral interrupt handler's name please refer to the startup */ +/* file (startup_stm32fxxx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles PPP interrupt request. + * @param None + * @retval None + */ +/*void PPP_IRQHandler(void) +{ +}*/ + +/** + * @brief This function handles EXTI0_IRQ Handler. + * @param None + * @retval None + */ +void EXTI0_IRQHandler(void) +{ + UserButtonPressed = 0x01; + + /* Clear the EXTI line pending bit */ + EXTI_ClearITPendingBit(USER_BUTTON_EXTI_LINE); +} + +/** + * @brief This function handles EXTI15_10_IRQ Handler. + * @param None + * @retval None + */ +void OTG_FS_WKUP_IRQHandler(void) +{ + if(USB_OTG_dev.cfg.low_power) + { + /* Reset SLEEPDEEP and SLEEPONEXIT bits */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + + /* After wake-up from sleep mode, reconfigure the system clock */ + SystemInit(); + USB_OTG_UngateClock(&USB_OTG_dev); + } + EXTI_ClearITPendingBit(EXTI_Line18); +} + +/** + * @brief This function handles OTG_HS Handler. + * @param None + * @retval None + */ +void OTG_FS_IRQHandler(void) +{ + USBD_OTG_ISR_Handler (&USB_OTG_dev); +} + +/** +* @brief USBD_HID_GetPos +* @param None +* @retval Pointer to report +*/ +static uint8_t *USBD_HID_GetPos (void) +{ + static uint8_t HID_Buffer[4] = {0}; + + HID_Buffer[1] = 0; + HID_Buffer[2] = 0; + /* LEFT Direction */ + if(((int8_t)Buffer[2]) < -2) + { + HID_Buffer[1] += CURSOR_STEP; + } + /* RIGHT Direction */ + if(((int8_t)Buffer[2]) > 2) + { + HID_Buffer[1] -= CURSOR_STEP; + } + /* UP Direction */ + if(((int8_t)Buffer[0]) < -2) + { + HID_Buffer[2] += CURSOR_STEP; + } + /* DOWN Direction */ + if(((int8_t)Buffer[0]) > 2) + { + HID_Buffer[2] -= CURSOR_STEP; + } + + return HID_Buffer; +} +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.h b/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.h new file mode 100644 index 0000000..4ae766c --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/stm32f4xx_it.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file stm32f4xx_it.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_IT_H +#define __STM32F4xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_IT_H */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/system_stm32f4xx.c b/example/stm32f4/Projects/discovery_demo/system_stm32f4xx.c new file mode 100644 index 0000000..fbb195c --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/system_stm32f4xx.c @@ -0,0 +1,566 @@ +/** + ****************************************************************************** + * @file system_stm32f4xx.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. + * This file contains the system clock configuration for STM32F4xx devices, + * and is generated by the clock configuration tool + * stm32f4xx_Clock_Configuration_V1.0.0.xls + * + * 1. This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier + * and Divider factors, AHB/APBx prescalers and Flash settings), + * depending on the configuration made in the clock xls tool. + * This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f4xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * 2. After each device reset the HSI (16 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to + * configure the system clock before to branch to main program. + * + * 3. If the system clock source selected by user fails to startup, the SystemInit() + * function will do nothing and HSI still used as system clock source. User can + * add some code to deal with this issue inside the SetSysClock() function. + * + * 4. The default value of HSE crystal is set to 8 MHz, refer to "HSE_VALUE" define + * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or + * through PLL, and you are using different crystal you have to adapt the HSE + * value to your own configuration. + * + * 5. This file configures the system clock as follows: + *============================================================================= + *============================================================================= + * Supported STM32F4xx device revision | Rev A + *----------------------------------------------------------------------------- + * System Clock source | PLL (HSE) + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 168000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 168000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 4 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 2 + *----------------------------------------------------------------------------- + * HSE Frequency(Hz) | 8000000 + *----------------------------------------------------------------------------- + * PLL_M | 8 + *----------------------------------------------------------------------------- + * PLL_N | 336 + *----------------------------------------------------------------------------- + * PLL_P | 2 + *----------------------------------------------------------------------------- + * PLL_Q | 7 + *----------------------------------------------------------------------------- + * PLLI2S_N | 192 + *----------------------------------------------------------------------------- + * PLLI2S_R | 5 + *----------------------------------------------------------------------------- + * I2S input clock(Hz) | 38400000 + *----------------------------------------------------------------------------- + * VDD(V) | 3.3 + *----------------------------------------------------------------------------- + * High Performance mode | Enabled + *----------------------------------------------------------------------------- + * Flash Latency(WS) | 5 + *----------------------------------------------------------------------------- + * Prefetch Buffer | OFF + *----------------------------------------------------------------------------- + * Instruction cache | ON + *----------------------------------------------------------------------------- + * Data cache | ON + *----------------------------------------------------------------------------- + * Require 48MHz for USB OTG FS, | Enabled + * SDIO and RNG clock | + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f4xx_system + * @{ + */ + +/** @addtogroup STM32F4xx_System_Private_Includes + * @{ + */ + +#include "stm32f4xx.h" + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Defines + * @{ + */ + +/*!< Uncomment the following line if you need to use external SRAM mounted + on STM324xG_EVAL board as data memory */ +/* #define DATA_IN_ExtSRAM */ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + + +/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ +#define PLL_M 8 +#define PLL_N 336 + +/* SYSCLK = PLL_VCO / PLL_P */ +#define PLL_P 2 + +/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ +#define PLL_Q 7 + +/* PLLI2S_VCO = (HSE_VALUE Or HSI_VALUE / PLL_M) * PLLI2S_N + I2SCLK = PLLI2S_VCO / PLLI2S_R */ +#define PLLI2S_N 192 +#define PLLI2S_R 5 + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Variables + * @{ + */ + + uint32_t SystemCoreClock = 168000000; + + __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes + * @{ + */ + +static void SetSysClock(void); +#ifdef DATA_IN_ExtSRAM + static void SystemInit_ExtMemCtl(void); +#endif /* DATA_IN_ExtSRAM */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemFrequency variable. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x24003010; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000; + +#ifdef DATA_IN_ExtSRAM + SystemInit_ExtMemCtl(); +#endif /* DATA_IN_ExtSRAM */ + + /* Configure the System clock source, PLL Multiplier and Divider factors, + AHB/APBx prescalers and Flash settings ----------------------------------*/ + SetSysClock(); + + /* Configure the Vector Table location add offset address ------------------*/ +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value + * 25 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock source */ + + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N + SYSCLK = PLL_VCO / PLL_P + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; + pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; + + if (pllsource != 0) + { + /* HSE used as PLL clock source */ + pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + else + { + /* HSI used as PLL clock source */ + pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + + pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; + SystemCoreClock = pllvco/pllp; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK frequency --------------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK frequency */ + SystemCoreClock >>= tmp; +} + +/** + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @Note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ +static void SetSysClock(void) +{ +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Enable high performance mode, System frequency up to 168 MHz */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + PWR->CR |= PWR_CR_PMODE; + + /* HCLK = SYSCLK / 1*/ + RCC->CFGR |= RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 2*/ + RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; + + /* PCLK1 = HCLK / 4*/ + RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; + + /* Configure the main PLL */ + RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | + (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); + + /* Enable the main PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till the main PLL is ready */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ + FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; + + /* Select the main PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= RCC_CFGR_SW_PLL; + + /* Wait till the main PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); + { + } + } + else + { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } + +/******************************************************************************/ +/* I2S clock configuration */ +/******************************************************************************/ + /* PLLI2S clock used as I2S clock source */ + RCC->CFGR &= ~RCC_CFGR_I2SSRC; + + /* Configure PLLI2S */ + RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28); + + /* Enable PLLI2S */ + RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON); + + /* Wait till PLLI2S is ready */ + while((RCC->CR & RCC_CR_PLLI2SRDY) == 0) + { + } +} + +/** + * @brief Setup the external memory controller. Called in startup_stm32f4xx.s + * before jump to __main + * @param None + * @retval None + */ +#ifdef DATA_IN_ExtSRAM +/** + * @brief Setup the external memory controller. + * Called in startup_stm32f4xx.s before jump to main. + * This function configures the external SRAM mounted on STM324xG_EVAL board + * This SRAM will be used as program data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ +/*-- GPIOs Configuration -----------------------------------------------------*/ +/* + +-------------------+--------------------+------------------+------------------+ + + SRAM pins assignment + + +-------------------+--------------------+------------------+------------------+ + | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 | + | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 | + | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 | + | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 | + | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 | + | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 | + | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 | + | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+ + | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 | + | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 | + | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+ + | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 | + | | PE15 <-> FSMC_D12 | + +-------------------+--------------------+ +*/ + /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */ + RCC->AHB1ENR = 0x00000078; + + /* Connect PDx pins to FSMC Alternate function */ + GPIOD->AFR[0] = 0x00cc00cc; + GPIOD->AFR[1] = 0xcc0ccccc; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xaaaa0a0a; + /* Configure PDx pins speed to 100 MHz */ + GPIOD->OSPEEDR = 0xffff0f0f; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x00000000; + + /* Connect PEx pins to FSMC Alternate function */ + GPIOE->AFR[0] = 0xc00cc0cc; + GPIOE->AFR[1] = 0xcccccccc; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xaaaa828a; + /* Configure PEx pins speed to 100 MHz */ + GPIOE->OSPEEDR = 0xffffc3cf; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x00000000; + + /* Connect PFx pins to FSMC Alternate function */ + GPIOF->AFR[0] = 0x00cccccc; + GPIOF->AFR[1] = 0xcccc0000; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xaa000aaa; + /* Configure PFx pins speed to 100 MHz */ + GPIOF->OSPEEDR = 0xff000fff; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x00000000; + + /* Connect PGx pins to FSMC Alternate function */ + GPIOG->AFR[0] = 0x00cccccc; + GPIOG->AFR[1] = 0x000000c0; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0x00080aaa; + /* Configure PGx pins speed to 100 MHz */ + GPIOG->OSPEEDR = 0x000c0fff; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x00000000; + +/*-- FSMC Configuration ------------------------------------------------------*/ + /* Enable the FSMC interface clock */ + RCC->AHB3ENR = 0x00000001; + + /* Configure and enable Bank1_SRAM2 */ + FSMC_Bank1->BTCR[2] = 0x00001015; + FSMC_Bank1->BTCR[3] = 0x00010603;//0x00010400; + FSMC_Bank1E->BWTR[2] = 0x0fffffff; +/* + Bank1_SRAM2 is configured as follow: + + p.FSMC_AddressSetupTime = 3;//0; + p.FSMC_AddressHoldTime = 0; + p.FSMC_DataSetupTime = 6;//4; + p.FSMC_BusTurnAroundDuration = 1; + p.FSMC_CLKDivision = 0; + p.FSMC_DataLatency = 0; + p.FSMC_AccessMode = FSMC_AccessMode_A; + + FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2; + FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; + FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM; + FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; + FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; + FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; + FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; + FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; + FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p; + FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; +*/ + +} +#endif /* DATA_IN_ExtSRAM */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/example/stm32f4/Projects/discovery_demo/usb_bsp.c b/example/stm32f4/Projects/discovery_demo/usb_bsp.c new file mode 100644 index 0000000..6861d65 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usb_bsp.c @@ -0,0 +1,382 @@ +/** + ****************************************************************************** + * @file usb_bsp.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file is responsible to offer board support package and is + * configurable by user. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_bsp.h" +#include "usbd_conf.h" +#include "stm32f4_discovery.h" + +//Library config for this project!!!!!!!!!!! +#include "stm32f4xx_conf.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY +* @{ +*/ + +/** @defgroup USB_BSP +* @brief This file is responsible to offer board support package +* @{ +*/ + +/** @defgroup USB_BSP_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_BSP_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + + + + +/** @defgroup USB_BSP_Private_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_BSP_Private_Variables +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBH_BSP_Private_FunctionPrototypes +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USB_BSP_Private_Functions +* @{ +*/ + + +/** +* @brief USB_OTG_BSP_Init +* Initilizes BSP configurations +* @param None +* @retval None +*/ + +void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) +{ + GPIO_InitTypeDef GPIO_InitStructure; + +#ifndef USE_ULPI_PHY +#ifdef USB_OTG_FS_LOW_PWR_MGMT_SUPPORT + EXTI_InitTypeDef EXTI_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; +#endif +#endif + + + #ifdef USE_USB_OTG_FS + + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE); + + /* Configure SOF VBUS ID DM DP Pins */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | + GPIO_Pin_9 | + GPIO_Pin_11 | + GPIO_Pin_12; + + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_OTG1_FS) ; + GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_OTG1_FS) ; + GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG1_FS) ; + GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG1_FS) ; + + /* this for ID line debug */ + + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_OTG1_FS) ; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ; + #else // USE_USB_OTG_HS + + #ifdef USE_ULPI_PHY // ULPI + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | + RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOH | + RCC_AHB1Periph_GPIOI, ENABLE); + + + GPIO_PinAFConfig(GPIOA,GPIO_PinSource3, GPIO_AF_OTG2_HS) ; // D0 + GPIO_PinAFConfig(GPIOA,GPIO_PinSource5, GPIO_AF_OTG2_HS) ; // CLK + GPIO_PinAFConfig(GPIOB,GPIO_PinSource0, GPIO_AF_OTG2_HS) ; // D1 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource1, GPIO_AF_OTG2_HS) ; // D2 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource5, GPIO_AF_OTG2_HS) ; // D7 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_OTG2_HS) ; // D3 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_OTG2_HS) ; // D4 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource12,GPIO_AF_OTG2_HS) ; // D5 + GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_OTG2_HS) ; // D6 + GPIO_PinAFConfig(GPIOH,GPIO_PinSource4, GPIO_AF_OTG2_HS) ; // NXT + GPIO_PinAFConfig(GPIOI,GPIO_PinSource11,GPIO_AF_OTG2_HS) ; // DIR + GPIO_PinAFConfig(GPIOC,GPIO_PinSource0, GPIO_AF_OTG2_HS) ; // STP + + // CLK + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + // D0 + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + + + // D1 D2 D3 D4 D5 D6 D7 + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | + GPIO_Pin_5 | GPIO_Pin_10 | + GPIO_Pin_11| GPIO_Pin_12 | + GPIO_Pin_13 ; + + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + + // STP + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + //NXT + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOH, &GPIO_InitStructure); + + + //DIR + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 ; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOI, &GPIO_InitStructure); + + + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_OTG_HS | + RCC_AHB1Periph_OTG_HS_ULPI, ENABLE) ; + + #else + #ifdef USE_I2C_PHY + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB , ENABLE); + /* Configure RESET INTN SCL SDA (Phy/I2C) Pins */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | + GPIO_Pin_1 | + GPIO_Pin_10 | + GPIO_Pin_11; + + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_OTG2_FS); + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_OTG_HS, ENABLE) ; + + #else + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | + GPIO_Pin_13 | + GPIO_Pin_14 | + GPIO_Pin_15; + + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOB,GPIO_PinSource12, GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_OTG2_FS) ; + GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_OTG2_FS) ; + RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_OTG_HS, ENABLE) ; + #endif + #endif // USE_ULPI_PHY + + #endif //USB_OTG_HS + + + /* enable the PWR clock */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_PWR, ENABLE); + + /* Configure the Key button in EXTI mode */ + STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_EXTI); + +#ifdef USB_OTG_FS_LOW_PWR_MGMT_SUPPORT + EXTI_ClearITPendingBit(EXTI_Line18); + + EXTI_InitStructure.EXTI_Line = EXTI_Line18; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + EXTI_ClearITPendingBit(EXTI_Line18); + + NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_WKUP_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + EXTI_ClearITPendingBit(EXTI_Line18); +#endif + +#ifdef USB_OTG_HS_LOW_PWR_MGMT_SUPPORT + EXTI_ClearITPendingBit(EXTI_Line20); + + EXTI_InitStructure.EXTI_Line = EXTI_Line20; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + EXTI_ClearITPendingBit(EXTI_Line20); + + NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_WKUP_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + EXTI_ClearITPendingBit(EXTI_Line20); +#endif + + EXTI_ClearITPendingBit(USER_BUTTON_EXTI_LINE); +} +/** +* @brief USB_OTG_BSP_EnableInterrupt +* Enabele USB Global interrupt +* @param None +* @retval None +*/ +void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev) +{ + NVIC_InitTypeDef NVIC_InitStructure; + + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); +#ifdef USE_USB_OTG_HS + NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_IRQn; +#else + NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn; +#endif + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_EP1_OUT_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_EP1_IN_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#endif +} +/** +* @brief USB_OTG_BSP_uDelay +* This function provides delay time in micro sec +* @param usec : Value of delay required in micro sec +* @retval None +*/ +void USB_OTG_BSP_uDelay (const uint32_t usec) +{ + uint32_t count = 0; + const uint32_t utime = (120 * usec / 7); + do + { + if ( ++count > utime ) + { + return ; + } + } + while (1); +} + + +/** +* @brief USB_OTG_BSP_mDelay +* This function provides delay time in milli sec +* @param msec : Value of delay required in milli sec +* @retval None +*/ +void USB_OTG_BSP_mDelay (const uint32_t msec) +{ + USB_OTG_BSP_uDelay(msec * 1000); +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/usb_conf.h b/example/stm32f4/Projects/discovery_demo/usb_conf.h new file mode 100644 index 0000000..eeb2f79 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usb_conf.h @@ -0,0 +1,252 @@ +/** + ****************************************************************************** + * @file usb_conf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CONF__H__ +#define __USB_CONF__H__ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx.h" + + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_CONF + * @brief USB low level driver configuration file + * @{ + */ + +/** @defgroup USB_CONF_Exported_Defines + * @{ + */ + +/* USB Core and PHY interface configuration. + Tip: To avoid modifying these defines each time you need to change the USB + configuration, you can declare the needed define in your toolchain + compiler preprocessor. + */ +#ifndef USE_USB_OTG_FS + //#define USE_USB_OTG_FS +#endif /* USE_USB_OTG_FS */ + +#ifdef USE_USB_OTG_FS + #define USB_OTG_FS_CORE +#endif + +/******************************************************************************* +* FIFO Size Configuration in Device mode +* +* (i) Receive data FIFO size = RAM for setup packets + +* OUT endpoint control information + +* data OUT packets + miscellaneous +* Space = ONE 32-bits words +* --> RAM for setup packets = 10 spaces +* (n is the nbr of CTRL EPs the device core supports) +* --> OUT EP CTRL info = 1 space +* (one space for status information written to the FIFO along with each +* received packet) +* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces +* (MINIMUM to receive packets) +* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces +* (if high-bandwidth EP is enabled or multiple isochronous EPs) +* --> miscellaneous = 1 space per OUT EP +* (one space for transfer complete status information also pushed to the +* FIFO with each endpoint's last packet) +* +* (ii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for +* that particular IN EP. More space allocated in the IN EP Tx FIFO results +* in a better performance on the USB and can hide latencies on the AHB. +* +* (iii) TXn min size = 16 words. (n : Transmit FIFO index) +* (iv) When a TxFIFO is not used, the Configuration should be as follows: +* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes) +* --> Txm can use the space allocated for Txn. +* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes) +* --> Txn should be configured with the minimum space of 16 words +* (v) The FIFO is used optimally when used TxFIFOs are allocated in the top +* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones. +*******************************************************************************/ + + + +/****************** USB OTG FS CONFIGURATION **********************************/ +#ifdef USB_OTG_FS_CORE + #define RX_FIFO_FS_SIZE 128 + #define TX0_FIFO_FS_SIZE 64 + #define TX1_FIFO_FS_SIZE 128 + #define TX2_FIFO_FS_SIZE 0 + #define TX3_FIFO_FS_SIZE 0 + + //#define USB_OTG_FS_LOW_PWR_MGMT_SUPPORT + //#define USB_OTG_FS_SOF_OUTPUT_ENABLED +#endif + +/****************** USB OTG MODE CONFIGURATION ********************************/ + +//#define USE_HOST_MODE +#define USE_DEVICE_MODE +//#define USE_OTG_MODE + + +#ifndef USB_OTG_FS_CORE + #ifndef USB_OTG_HS_CORE + #error "USB_OTG_HS_CORE or USB_OTG_FS_CORE should be defined" + #endif +#endif + + +#ifndef USE_DEVICE_MODE + #ifndef USE_HOST_MODE + #error "USE_DEVICE_MODE or USE_HOST_MODE should be defined" + #endif +#endif + +#ifndef USE_USB_OTG_HS + #ifndef USE_USB_OTG_FS + #error "USE_USB_OTG_HS or USE_USB_OTG_FS should be defined" + #endif +#else //USE_USB_OTG_HS + #ifndef USE_ULPI_PHY + #ifndef USE_EMBEDDED_PHY + #ifndef USE_I2C_PHY + #error "USE_ULPI_PHY or USE_EMBEDDED_PHY or USE_I2C_PHY should be defined" + #endif + #endif + #endif +#endif + +/****************** C Compilers dependant keywords ****************************/ +/* In HS mode and when the DMA is used, all variables and data structures dealing + with the DMA during the transaction process should be 4-bytes aligned */ +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined (__GNUC__) /* GNU Compiler */ + #define __ALIGN_END __attribute__ ((aligned (4))) + #define __ALIGN_BEGIN + #else + #define __ALIGN_END + #if defined (__CC_ARM) /* ARM Compiler */ + #define __ALIGN_BEGIN __align(4) + #elif defined (__ICCARM__) /* IAR Compiler */ + #define __ALIGN_BEGIN + #elif defined (__TASKING__) /* TASKING Compiler */ + #define __ALIGN_BEGIN __align(4) + #endif /* __CC_ARM */ + #endif /* __GNUC__ */ +#else + #define __ALIGN_BEGIN + #define __ALIGN_END +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ + +/* __packed keyword used to decrease the data type alignment to 1-byte */ +#if defined (__CC_ARM) /* ARM Compiler */ + #define __packed __packed +#elif defined (__ICCARM__) /* IAR Compiler */ + #define __packed __packed +#elif defined ( __GNUC__ ) /* GNU Compiler */ + #define __packed __attribute__ ((__packed__)) +#elif defined (__TASKING__) /* TASKING Compiler */ + #define __packed __unaligned +#endif /* __CC_ARM */ + +/****************** C Compilers dependant keywords ****************************/ +/* In HS mode and when the DMA is used, all variables and data structures dealing + with the DMA during the transaction process should be 4-bytes aligned */ +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined (__GNUC__) /* GNU Compiler */ + #define __ALIGN_END __attribute__ ((aligned (4))) + #define __ALIGN_BEGIN + #else + #define __ALIGN_END + #if defined (__CC_ARM) /* ARM Compiler */ + #define __ALIGN_BEGIN __align(4) + #elif defined (__ICCARM__) /* IAR Compiler */ + #define __ALIGN_BEGIN + #elif defined (__TASKING__) /* TASKING Compiler */ + #define __ALIGN_BEGIN __align(4) + #endif /* __CC_ARM */ + #endif /* __GNUC__ */ +#else + #define __ALIGN_BEGIN + #define __ALIGN_END +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ + +/* __packed keyword used to decrease the data type alignment to 1-byte */ +#if defined (__CC_ARM) /* ARM Compiler */ + #define __packed __packed +#elif defined (__ICCARM__) /* IAR Compiler */ + #define __packed __packed +#elif defined ( __GNUC__ ) /* GNU Compiler */ + #define __packed __attribute__ ((__packed__)) +#elif defined (__TASKING__) /* TASKING Compiler */ + #define __packed __unaligned +#endif /* __CC_ARM */ + + +/** + * @} + */ + + +/** @defgroup USB_CONF_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USB_CONF_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_CONF_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_CONF_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + + +#endif //__USB_CONF__H__ + + +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/example/stm32f4/Projects/discovery_demo/usb_core.c b/example/stm32f4/Projects/discovery_demo/usb_core.c new file mode 100644 index 0000000..74e432a --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usb_core.c @@ -0,0 +1,2187 @@ +/** + ****************************************************************************** + * @file usb_core.c + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief USB-OTG Core Layer + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_core.h" +#include "usb_bsp.h" + + +/** @addtogroup USB_OTG_DRIVER +* @{ +*/ + +/** @defgroup USB_CORE +* @brief This file includes the USB-OTG Core Layer +* @{ +*/ + + +/** @defgroup USB_CORE_Private_Defines +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USB_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + + +/** @defgroup USB_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_CORE_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_CORE_Private_FunctionPrototypes +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_CORE_Private_Functions +* @{ +*/ + +/** +* @brief USB_OTG_EnableCommonInt +* Initializes the commmon interrupts, used in both device and modes +* @param pdev : Selected device +* @retval None +*/ +static void USB_OTG_EnableCommonInt(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTMSK_TypeDef int_mask; + + int_mask.d32 = 0; + /* Clear any pending USB_OTG Interrupts */ +#ifndef USE_OTG_MODE + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GOTGINT, 0xFFFFFFFF); +#endif + /* Clear any pending interrupts */ + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); + /* Enable the interrupts in the INTMSK */ + int_mask.b.wkupintr = 1; + int_mask.b.usbsuspend = 1; + +#ifdef USE_OTG_MODE + int_mask.b.otgintr = 1; + int_mask.b.sessreqintr = 1; + int_mask.b.conidstschng = 1; +#endif + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTMSK, int_mask.d32); +} + +/** +* @brief USB_OTG_CoreReset : Soft reset of the core +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +static USB_OTG_STS USB_OTG_CoreReset(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + __IO USB_OTG_GRSTCTL_TypeDef greset; + uint32_t count = 0; + + greset.d32 = 0; + /* Wait for AHB master IDLE state. */ + do + { + USB_OTG_BSP_uDelay(3); + greset.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRSTCTL); + if (++count > 200000) + { + return USB_OTG_OK; + } + } + while (greset.b.ahbidle == 0); + /* Core Soft Reset */ + count = 0; + greset.b.csftrst = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRSTCTL, greset.d32 ); + do + { + greset.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRSTCTL); + if (++count > 200000) + { + break; + } + } + while (greset.b.csftrst == 1); + /* Wait for 3 PHY Clocks*/ + USB_OTG_BSP_uDelay(3); + return status; +} + +/** +* @brief USB_OTG_WritePacket : Writes a packet into the Tx FIFO associated +* with the EP +* @param pdev : Selected device +* @param src : source pointer +* @param ch_ep_num : end point number +* @param bytes : No. of bytes +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_WritePacket(USB_OTG_CORE_HANDLE *pdev, + uint8_t *src, + uint8_t ch_ep_num, + uint16_t len) +{ + USB_OTG_STS status = USB_OTG_OK; + if (pdev->cfg.dma_enable == 0) + { + uint32_t count32b= 0 , i= 0; + __IO uint32_t *fifo; + + count32b = (len + 3) / 4; + fifo = pdev->regs.DFIFO[ch_ep_num]; + for (i = 0; i < count32b; i++, src+=4) + { + USB_OTG_WRITE_REG32( fifo, *((__packed uint32_t *)src) ); + } + } + return status; +} + + +/** +* @brief USB_OTG_ReadPacket : Reads a packet from the Rx FIFO +* @param pdev : Selected device +* @param dest : Destination Pointer +* @param bytes : No. of bytes +* @retval None +*/ +void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev, + uint8_t *dest, + uint16_t len) +{ + uint32_t i=0; + uint32_t count32b = (len + 3) / 4; + + __IO uint32_t *fifo = pdev->regs.DFIFO[0]; + + for ( i = 0; i < count32b; i++, dest += 4 ) + { + *(__packed uint32_t *)dest = USB_OTG_READ_REG32(fifo); + + } + return ((void *)dest); +} + +/** +* @brief USB_OTG_SelectCore +* Initialize core registers address. +* @param pdev : Selected device +* @param coreID : USB OTG Core ID +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_SelectCore(USB_OTG_CORE_HANDLE *pdev, + USB_OTG_CORE_ID_TypeDef coreID) +{ + uint32_t i , baseAddress = 0; + USB_OTG_STS status = USB_OTG_OK; + + pdev->cfg.dma_enable = 0; + + /* at startup the core is in FS mode */ + pdev->cfg.speed = USB_OTG_SPEED_FULL; + pdev->cfg.mps = USB_OTG_FS_MAX_PACKET_SIZE ; + + /* initialize device cfg following its address */ + if (coreID == USB_OTG_FS_CORE_ID) + { + baseAddress = USB_OTG_FS_BASE_ADDR; + pdev->cfg.coreID = USB_OTG_FS_CORE_ID; + pdev->cfg.host_channels = 8 ; + pdev->cfg.dev_endpoints = 4 ; + pdev->cfg.TotalFifoSize = 320; /* in 32-bits */ + pdev->cfg.phy_itface = USB_OTG_EMBEDDED_PHY; + +#ifdef USB_OTG_FS_SOF_OUTPUT_ENABLED + pdev->cfg.Sof_output = 1; +#endif + +#ifdef USB_OTG_FS_LOW_PWR_MGMT_SUPPORT + pdev->cfg.low_power = 1; +#endif + } + else if (coreID == USB_OTG_HS_CORE_ID) + { + baseAddress = USB_OTG_HS_BASE_ADDR; + pdev->cfg.coreID = USB_OTG_HS_CORE_ID; + pdev->cfg.host_channels = 12 ; + pdev->cfg.dev_endpoints = 6 ; + pdev->cfg.TotalFifoSize = 1280;/* in 32-bits */ + +#ifdef USB_OTG_ULPI_PHY_ENABLED + pdev->cfg.phy_itface = USB_OTG_ULPI_PHY; +#else + #ifdef USB_OTG_EMBEDDED_PHY_ENABLED + pdev->cfg.phy_itface = USB_OTG_EMBEDDED_PHY; + #else + #ifdef USB_OTG_I2C_PHY_ENABLED + pdev->cfg.phy_itface = USB_OTG_I2C_PHY; + #endif + #endif +#endif + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + pdev->cfg.dma_enable = 1; +#endif + +#ifdef USB_OTG_HS_SOF_OUTPUT_ENABLED + pdev->cfg.Sof_output = 1; +#endif + +#ifdef USB_OTG_HS_LOW_PWR_MGMT_SUPPORT + pdev->cfg.low_power = 1; +#endif + + } + + pdev->regs.GREGS = (USB_OTG_GREGS *)(baseAddress + \ + USB_OTG_CORE_GLOBAL_REGS_OFFSET); + pdev->regs.DREGS = (USB_OTG_DREGS *) (baseAddress + \ + USB_OTG_DEV_GLOBAL_REG_OFFSET); + + for (i = 0; i < pdev->cfg.dev_endpoints; i++) + { + pdev->regs.INEP_REGS[i] = (USB_OTG_INEPREGS *) \ + (baseAddress + USB_OTG_DEV_IN_EP_REG_OFFSET + \ + (i * USB_OTG_EP_REG_OFFSET)); + pdev->regs.OUTEP_REGS[i] = (USB_OTG_OUTEPREGS *) \ + (baseAddress + USB_OTG_DEV_OUT_EP_REG_OFFSET + \ + (i * USB_OTG_EP_REG_OFFSET)); + } + pdev->regs.HREGS = (USB_OTG_HREGS *)(baseAddress + \ + USB_OTG_HOST_GLOBAL_REG_OFFSET); + pdev->regs.HPRT0 = (uint32_t *)(baseAddress + USB_OTG_HOST_PORT_REGS_OFFSET); + + for (i = 0; i < pdev->cfg.host_channels; i++) + { + pdev->regs.HC_REGS[i] = (USB_OTG_HC_REGS *)(baseAddress + \ + USB_OTG_HOST_CHAN_REGS_OFFSET + \ + (i * USB_OTG_CHAN_REGS_OFFSET)); + } + for (i = 0; i < pdev->cfg.host_channels; i++) + { + pdev->regs.DFIFO[i] = (uint32_t *)(baseAddress + USB_OTG_DATA_FIFO_OFFSET +\ + (i * USB_OTG_DATA_FIFO_SIZE)); + } + pdev->regs.PCGCCTL = (uint32_t *)(baseAddress + USB_OTG_PCGCCTL_OFFSET); + + return status; +} + + +/** +* @brief USB_OTG_CoreInit +* Initializes the USB_OTG controller registers and prepares the core +* device mode or host mode operation. +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_CoreInit(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GUSBCFG_TypeDef usbcfg; + USB_OTG_GCCFG_TypeDef gccfg; + USB_OTG_GI2CCTL_TypeDef i2cctl; + USB_OTG_GAHBCFG_TypeDef ahbcfg; + + usbcfg.d32 = 0; + gccfg.d32 = 0; + ahbcfg.d32 = 0; + + + + if (pdev->cfg.phy_itface == USB_OTG_ULPI_PHY) + { + gccfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GCCFG); + gccfg.b.pwdn = 0; + + if (pdev->cfg.Sof_output) + { + gccfg.b.sofouten = 1; + } + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GCCFG, gccfg.d32); + + /* Init The ULPI Interface */ + usbcfg.d32 = 0; + usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); + + usbcfg.b.physel = 0; /* HS Interface */ +#ifdef USB_OTG_INTERNAL_VBUS_ENABLED + usbcfg.b.ulpi_ext_vbus_drv = 0; /* Use internal VBUS */ +#else + #ifdef USB_OTG_EXTERNAL_VBUS_ENABLED + usbcfg.b.ulpi_ext_vbus_drv = 1; /* Use external VBUS */ + #endif +#endif + usbcfg.b.term_sel_dl_pulse = 0; /* Data line pulsing using utmi_txvalid */ + usbcfg.b.ulpi_utmi_sel = 1; /* ULPI seleInterfacect */ + + usbcfg.b.phyif = 0; /* 8 bits */ + usbcfg.b.ddrsel = 0; /* single data rate */ + + usbcfg.b.ulpi_fsls = 0; + usbcfg.b.ulpi_clk_sus_m = 0; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); + + /* Reset after a PHY select */ + USB_OTG_CoreReset(pdev); + + if(pdev->cfg.dma_enable == 1) + { + + ahbcfg.b.hburstlen = 5; /* 64 x 32-bits*/ + ahbcfg.b.dmaenable = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32); + + } + } + else /* FS interface (embedded Phy or I2C Phy) */ + { + + usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG);; + usbcfg.b.physel = 1; /* FS Interface */ + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); + /* Reset after a PHY select and set Host mode */ + USB_OTG_CoreReset(pdev); + /* Enable the I2C interface and deactivate the power down*/ + gccfg.d32 = 0; + gccfg.b.pwdn = 1; + + if(pdev->cfg.phy_itface == USB_OTG_I2C_PHY) + { + gccfg.b.i2cifen = 1; + } + gccfg.b.vbussensingA = 1 ; + gccfg.b.vbussensingB = 1 ; +#ifndef VBUS_SENSING_ENABLED + gccfg.b.disablevbussensing = 1; +#endif + + if(pdev->cfg.Sof_output) + { + gccfg.b.sofouten = 1; + } + + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GCCFG, gccfg.d32); + USB_OTG_BSP_mDelay(20); + /* Program GUSBCFG.OtgUtmifsSel to I2C*/ + usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); + + if(pdev->cfg.phy_itface == USB_OTG_I2C_PHY) + { + usbcfg.b.otgutmifssel = 1; + } + + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); + + if(pdev->cfg.phy_itface == USB_OTG_I2C_PHY) + { + /*Program GI2CCTL.I2CEn*/ + i2cctl.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GI2CCTL); + i2cctl.b.i2cdevaddr = 1; + i2cctl.b.i2cen = 0; + i2cctl.b.dat_se0 = 1; + i2cctl.b.addr = 0x2D; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GI2CCTL, i2cctl.d32); + + USB_OTG_BSP_mDelay(200); + + i2cctl.b.i2cen = 1; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GI2CCTL, i2cctl.d32); + USB_OTG_BSP_mDelay(200); + } + } + /* case the HS core is working in FS mode */ + if(pdev->cfg.dma_enable == 1) + { + + ahbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GAHBCFG); + ahbcfg.b.hburstlen = 5; /* 64 x 32-bits*/ + ahbcfg.b.dmaenable = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32); + + } + /* initialize OTG features */ +#ifdef USE_OTG_MODE + usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); + usbcfg.b.hnpcap = 1; + usbcfg.b.srpcap = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); + USB_OTG_EnableCommonInt(pdev); +#endif + return status; +} +/** +* @brief USB_OTG_EnableGlobalInt +* Enables the controller's Global Int in the AHB Config reg +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EnableGlobalInt(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GAHBCFG_TypeDef ahbcfg; + + ahbcfg.d32 = 0; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GAHBCFG, 0, ahbcfg.d32); + return status; +} + + +/** +* @brief USB_OTG_DisableGlobalInt +* Enables the controller's Global Int in the AHB Config reg +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_DisableGlobalInt(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GAHBCFG_TypeDef ahbcfg; + ahbcfg.d32 = 0; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GAHBCFG, ahbcfg.d32, 0); + return status; +} + + +/** +* @brief USB_OTG_FlushTxFifo : Flush a Tx FIFO +* @param pdev : Selected device +* @param num : FO num +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_FlushTxFifo (USB_OTG_CORE_HANDLE *pdev , uint32_t num ) +{ + USB_OTG_STS status = USB_OTG_OK; + __IO USB_OTG_GRSTCTL_TypeDef greset; + + uint32_t count = 0; + greset.d32 = 0; + greset.b.txfflsh = 1; + greset.b.txfnum = num; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GRSTCTL, greset.d32 ); + do + { + greset.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRSTCTL); + if (++count > 200000) + { + break; + } + } + while (greset.b.txfflsh == 1); + /* Wait for 3 PHY Clocks*/ + USB_OTG_BSP_uDelay(3); + return status; +} + + +/** +* @brief USB_OTG_FlushRxFifo : Flush a Rx FIFO +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_FlushRxFifo( USB_OTG_CORE_HANDLE *pdev ) +{ + USB_OTG_STS status = USB_OTG_OK; + __IO USB_OTG_GRSTCTL_TypeDef greset; + uint32_t count = 0; + + greset.d32 = 0; + greset.b.rxfflsh = 1; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GRSTCTL, greset.d32 ); + do + { + greset.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRSTCTL); + if (++count > 200000) + { + break; + } + } + while (greset.b.rxfflsh == 1); + /* Wait for 3 PHY Clocks*/ + USB_OTG_BSP_uDelay(3); + return status; +} + + +/** +* @brief USB_OTG_SetCurrentMode : Set ID line +* @param pdev : Selected device +* @param mode : (Host/device) +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_SetCurrentMode(USB_OTG_CORE_HANDLE *pdev , uint8_t mode) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GUSBCFG_TypeDef usbcfg; + + usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); + + usbcfg.b.force_host = 0; + usbcfg.b.force_dev = 0; + + if ( mode == HOST_MODE) + { + usbcfg.b.force_host = 1; + } + else if ( mode == DEVICE_MODE) + { + usbcfg.b.force_dev = 1; + } + + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); + USB_OTG_BSP_mDelay(50); + return status; +} + + +/** +* @brief USB_OTG_GetMode : Get current mode +* @param pdev : Selected device +* @retval current mode +*/ +uint32_t USB_OTG_GetMode(USB_OTG_CORE_HANDLE *pdev) +{ + return (USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTSTS ) & 0x1); +} + + +/** +* @brief USB_OTG_IsDeviceMode : Check if it is device mode +* @param pdev : Selected device +* @retval num_in_ep +*/ +uint8_t USB_OTG_IsDeviceMode(USB_OTG_CORE_HANDLE *pdev) +{ + return (USB_OTG_GetMode(pdev) != HOST_MODE); +} + + +/** +* @brief USB_OTG_IsHostMode : Check if it is host mode +* @param pdev : Selected device +* @retval num_in_ep +*/ +uint8_t USB_OTG_IsHostMode(USB_OTG_CORE_HANDLE *pdev) +{ + return (USB_OTG_GetMode(pdev) == HOST_MODE); +} + + +/** +* @brief USB_OTG_ReadCoreItr : returns the Core Interrupt register +* @param pdev : Selected device +* @retval Status +*/ +uint32_t USB_OTG_ReadCoreItr(USB_OTG_CORE_HANDLE *pdev) +{ + uint32_t v = 0; + v = USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTSTS); + v &= USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTMSK); + return v; +} + + +/** +* @brief USB_OTG_ReadOtgItr : returns the USB_OTG Interrupt register +* @param pdev : Selected device +* @retval Status +*/ +uint32_t USB_OTG_ReadOtgItr (USB_OTG_CORE_HANDLE *pdev) +{ + return (USB_OTG_READ_REG32 (&pdev->regs.GREGS->GOTGINT)); +} + +#ifdef USE_HOST_MODE +/** +* @brief USB_OTG_CoreInitHost : Initializes USB_OTG controller for host mode +* @param pdev : Selected device +* @retval status +*/ +USB_OTG_STS USB_OTG_CoreInitHost(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_FSIZ_TypeDef nptxfifosize; + USB_OTG_FSIZ_TypeDef ptxfifosize; + USB_OTG_HCFG_TypeDef hcfg; + +#ifdef USE_OTG_MODE + USB_OTG_OTGCTL_TypeDef gotgctl; +#endif + + uint32_t i = 0; + + nptxfifosize.d32 = 0; + ptxfifosize.d32 = 0; +#ifdef USE_OTG_MODE + gotgctl.d32 = 0; +#endif + hcfg.d32 = 0; + + + /* configure charge pump IO */ + USB_OTG_BSP_ConfigVBUS(pdev); + + /* Restart the Phy Clock */ + USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, 0); + + /* Initialize Host Configuration Register */ + USB_OTG_InitFSLSPClkSel(pdev , HCFG_48_MHZ); /* in init phase */ + + hcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HCFG); + hcfg.b.fslssupp = 0; + USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HCFG, hcfg.d32); + + /* Configure data FIFO sizes */ + /* Rx FIFO */ +#ifdef USB_OTG_FS_CORE + if(pdev->cfg.coreID == USB_OTG_FS_CORE_ID) + { + /* set Rx FIFO size */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_FS_SIZE); + nptxfifosize.b.startaddr = RX_FIFO_FS_SIZE; + nptxfifosize.b.depth = TXH_NP_FS_FIFOSIZ; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32); + + ptxfifosize.b.startaddr = RX_FIFO_FS_SIZE + TXH_NP_FS_FIFOSIZ; + ptxfifosize.b.depth = TXH_P_FS_FIFOSIZ; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->HPTXFSIZ, ptxfifosize.d32); + } +#endif +#ifdef USB_OTG_HS_CORE + if (pdev->cfg.coreID == USB_OTG_HS_CORE_ID) + { + /* set Rx FIFO size */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_HS_SIZE); + nptxfifosize.b.startaddr = RX_FIFO_HS_SIZE; + nptxfifosize.b.depth = TXH_NP_HS_FIFOSIZ; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32); + + ptxfifosize.b.startaddr = RX_FIFO_HS_SIZE + TXH_NP_HS_FIFOSIZ; + ptxfifosize.b.depth = TXH_P_HS_FIFOSIZ; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->HPTXFSIZ, ptxfifosize.d32); + } +#endif + +#ifdef USE_OTG_MODE + /* Clear Host Set HNP Enable in the USB_OTG Control Register */ + gotgctl.b.hstsethnpen = 1; + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GOTGCTL, gotgctl.d32, 0); +#endif + + /* Make sure the FIFOs are flushed. */ + USB_OTG_FlushTxFifo(pdev, 0x10 ); /* all Tx FIFOs */ + USB_OTG_FlushRxFifo(pdev); + + + /* Clear all pending HC Interrupts */ + for (i = 0; i < pdev->cfg.host_channels; i++) + { + USB_OTG_WRITE_REG32( &pdev->regs.HC_REGS[i]->HCINT, 0xFFFFFFFF ); + USB_OTG_WRITE_REG32( &pdev->regs.HC_REGS[i]->HCGINTMSK, 0 ); + } +#ifndef USE_OTG_MODE + USB_OTG_DriveVbus(pdev, 1); +#endif + + USB_OTG_EnableHostInt(pdev); + return status; +} + +/** +* @brief USB_OTG_IsEvenFrame +* This function returns the frame number for sof packet +* @param pdev : Selected device +* @retval Frame number +*/ +uint8_t USB_OTG_IsEvenFrame (USB_OTG_CORE_HANDLE *pdev) +{ + return !(USB_OTG_READ_REG32(&pdev->regs.HREGS->HFNUM) & 0x1); +} + +/** +* @brief USB_OTG_DriveVbus : set/reset vbus +* @param pdev : Selected device +* @param state : VBUS state +* @retval None +*/ +void USB_OTG_DriveVbus (USB_OTG_CORE_HANDLE *pdev, uint8_t state) +{ + USB_OTG_HPRT0_TypeDef hprt0; + + hprt0.d32 = 0; + + /* enable disable the external charge pump */ + USB_OTG_BSP_DriveVBUS(pdev, state); + + /* Turn on the Host port power. */ + hprt0.d32 = USB_OTG_ReadHPRT0(pdev); + if ((hprt0.b.prtpwr == 0 ) && (state == 1 )) + { + hprt0.b.prtpwr = 1; + USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); + } + if ((hprt0.b.prtpwr == 1 ) && (state == 0 )) + { + hprt0.b.prtpwr = 0; + USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); + } + + USB_OTG_BSP_mDelay(200); +} +/** +* @brief USB_OTG_EnableHostInt: Enables the Host mode interrupts +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EnableHostInt(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GINTMSK_TypeDef intmsk; + intmsk.d32 = 0; + /* Disable all interrupts. */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTMSK, 0); + + /* Clear any pending interrupts. */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); + + /* Enable the common interrupts */ + USB_OTG_EnableCommonInt(pdev); + + if (pdev->cfg.dma_enable == 0) + { + intmsk.b.rxstsqlvl = 1; + } + intmsk.b.portintr = 1; + intmsk.b.hcintr = 1; + intmsk.b.disconnect = 1; + intmsk.b.sofintr = 1; + intmsk.b.incomplisoout = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); + return status; +} + +/** +* @brief USB_OTG_InitFSLSPClkSel : Initializes the FSLSPClkSel field of the +* HCFG register on the PHY type +* @param pdev : Selected device +* @param freq : clock frequency +* @retval None +*/ +void USB_OTG_InitFSLSPClkSel(USB_OTG_CORE_HANDLE *pdev , uint8_t freq) +{ + USB_OTG_HCFG_TypeDef hcfg; + + hcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HCFG); + hcfg.b.fslspclksel = freq; + USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HCFG, hcfg.d32); +} + + +/** +* @brief USB_OTG_ReadHPRT0 : Reads HPRT0 to modify later +* @param pdev : Selected device +* @retval HPRT0 value +*/ +uint32_t USB_OTG_ReadHPRT0(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_HPRT0_TypeDef hprt0; + + hprt0.d32 = USB_OTG_READ_REG32(pdev->regs.HPRT0); + hprt0.b.prtena = 0; + hprt0.b.prtconndet = 0; + hprt0.b.prtenchng = 0; + hprt0.b.prtovrcurrchng = 0; + return hprt0.d32; +} + + +/** +* @brief USB_OTG_ReadHostAllChannels_intr : Register PCD Callbacks +* @param pdev : Selected device +* @retval Status +*/ +uint32_t USB_OTG_ReadHostAllChannels_intr (USB_OTG_CORE_HANDLE *pdev) +{ + return (USB_OTG_READ_REG32 (&pdev->regs.HREGS->HAINT)); +} + + +/** +* @brief USB_OTG_ResetPort : Reset Host Port +* @param pdev : Selected device +* @retval status +* @note : (1)The application must wait at least 10 ms (+ 10 ms security) +* before clearing the reset bit. +*/ +uint32_t USB_OTG_ResetPort(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_HPRT0_TypeDef hprt0; + + hprt0.d32 = USB_OTG_ReadHPRT0(pdev); + hprt0.b.prtrst = 1; + USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); + USB_OTG_BSP_mDelay (10); /* See Note #1 */ + hprt0.b.prtrst = 0; + USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0.d32); + USB_OTG_BSP_mDelay (20); + return 1; +} + + +/** +* @brief USB_OTG_HC_Init : Prepares a host channel for transferring packets +* @param pdev : Selected device +* @param hc_num : channel number +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_HC_Init(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) +{ + USB_OTG_STS status = USB_OTG_OK; + uint32_t intr_enable = 0; + USB_OTG_HCGINTMSK_TypeDef hcintmsk; + USB_OTG_GINTMSK_TypeDef gintmsk; + USB_OTG_HCCHAR_TypeDef hcchar; + USB_OTG_HCINTn_TypeDef hcint; + + + gintmsk.d32 = 0; + hcintmsk.d32 = 0; + hcchar.d32 = 0; + + /* Clear old interrupt conditions for this host channel. */ + hcint.d32 = 0xFFFFFFFF; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCINT, hcint.d32); + + /* Enable channel interrupts required for this transfer. */ + hcintmsk.d32 = 0; + + if (pdev->cfg.dma_enable == 1) + { + hcintmsk.b.ahberr = 1; + } + + switch (pdev->host.hc[hc_num].ep_type) + { + case EP_TYPE_CTRL: + case EP_TYPE_BULK: + hcintmsk.b.xfercompl = 1; + hcintmsk.b.stall = 1; + hcintmsk.b.xacterr = 1; + hcintmsk.b.datatglerr = 1; + hcintmsk.b.nak = 1; + if (pdev->host.hc[hc_num].ep_is_in) + { + hcintmsk.b.bblerr = 1; + } + else + { + hcintmsk.b.nyet = 1; + if (pdev->host.hc[hc_num].do_ping) + { + hcintmsk.b.ack = 1; + } + } + break; + case EP_TYPE_INTR: + hcintmsk.b.xfercompl = 1; + hcintmsk.b.nak = 1; + hcintmsk.b.stall = 1; + hcintmsk.b.xacterr = 1; + hcintmsk.b.datatglerr = 1; + hcintmsk.b.frmovrun = 1; + + if (pdev->host.hc[hc_num].ep_is_in) + { + hcintmsk.b.bblerr = 1; + } + + break; + case EP_TYPE_ISOC: + hcintmsk.b.xfercompl = 1; + hcintmsk.b.frmovrun = 1; + hcintmsk.b.ack = 1; + + if (pdev->host.hc[hc_num].ep_is_in) + { + hcintmsk.b.xacterr = 1; + hcintmsk.b.bblerr = 1; + } + break; + } + + + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCGINTMSK, hcintmsk.d32); + + + /* Enable the top level host channel interrupt. */ + intr_enable = (1 << hc_num); + USB_OTG_MODIFY_REG32(&pdev->regs.HREGS->HAINTMSK, 0, intr_enable); + + /* Make sure host channel interrupts are enabled. */ + gintmsk.b.hcintr = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, 0, gintmsk.d32); + + /* Program the HCCHAR register */ + hcchar.d32 = 0; + hcchar.b.devaddr = pdev->host.hc[hc_num].dev_addr; + hcchar.b.epnum = pdev->host.hc[hc_num].ep_num; + hcchar.b.epdir = pdev->host.hc[hc_num].ep_is_in; + hcchar.b.lspddev = (pdev->host.hc[hc_num].speed == HPRT0_PRTSPD_LOW_SPEED); + hcchar.b.eptype = pdev->host.hc[hc_num].ep_type; + hcchar.b.mps = pdev->host.hc[hc_num].max_packet; + if (pdev->host.hc[hc_num].ep_type == HCCHAR_INTR) + { + hcchar.b.oddfrm = 1; + } + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); + return status; +} + + +/** +* @brief USB_OTG_HC_StartXfer : Start transfer +* @param pdev : Selected device +* @param hc_num : channel number +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_HC_StartXfer(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_HCCHAR_TypeDef hcchar; + USB_OTG_HCTSIZn_TypeDef hctsiz; + USB_OTG_HNPTXSTS_TypeDef hnptxsts; + USB_OTG_HPTXSTS_TypeDef hptxsts; + USB_OTG_GINTMSK_TypeDef intmsk; + uint16_t len_words = 0; + + uint16_t num_packets; + uint16_t max_hc_pkt_count; + + max_hc_pkt_count = 256; + hctsiz.d32 = 0; + hcchar.d32 = 0; + intmsk.d32 = 0; + + /* Compute the expected number of packets associated to the transfer */ + if (pdev->host.hc[hc_num].xfer_len > 0) + { + num_packets = (pdev->host.hc[hc_num].xfer_len + \ + pdev->host.hc[hc_num].max_packet - 1) / pdev->host.hc[hc_num].max_packet; + + if (num_packets > max_hc_pkt_count) + { + num_packets = max_hc_pkt_count; + pdev->host.hc[hc_num].xfer_len = num_packets * \ + pdev->host.hc[hc_num].max_packet; + } + } + else + { + num_packets = 1; + } + if (pdev->host.hc[hc_num].ep_is_in) + { + pdev->host.hc[hc_num].xfer_len = num_packets * \ + pdev->host.hc[hc_num].max_packet; + } + /* Initialize the HCTSIZn register */ + hctsiz.b.xfersize = pdev->host.hc[hc_num].xfer_len; + hctsiz.b.pktcnt = num_packets; + hctsiz.b.pid = pdev->host.hc[hc_num].data_pid; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32); + + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCDMA, (unsigned int)pdev->host.hc[hc_num].xfer_buff); + } + + + hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); + hcchar.b.oddfrm = USB_OTG_IsEvenFrame(pdev); + + /* Set host channel enable */ + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); + + if (pdev->cfg.dma_enable == 0) /* Slave mode */ + { + if((pdev->host.hc[hc_num].ep_is_in == 0) && + (pdev->host.hc[hc_num].xfer_len > 0)) + { + switch(pdev->host.hc[hc_num].ep_type) + { + /* Non periodic transfer */ + case EP_TYPE_CTRL: + case EP_TYPE_BULK: + + hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); + len_words = (pdev->host.hc[hc_num].xfer_len + 3) / 4; + + /* check if there is enough space in FIFO space */ + if(len_words > hnptxsts.b.nptxfspcavail) + { + /* need to process data in nptxfempty interrupt */ + intmsk.b.nptxfempty = 1; + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, intmsk.d32); + } + + break; + /* Periodic transfer */ + case EP_TYPE_INTR: + case EP_TYPE_ISOC: + hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); + len_words = (pdev->host.hc[hc_num].xfer_len + 3) / 4; + /* check if there is enough space in FIFO space */ + if(len_words > hptxsts.b.ptxfspcavail) /* split the transfer */ + { + /* need to process data in ptxfempty interrupt */ + intmsk.b.ptxfempty = 1; + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, intmsk.d32); + } + break; + + default: + break; + } + + /* Write packet into the Tx FIFO. */ + USB_OTG_WritePacket(pdev, + pdev->host.hc[hc_num].xfer_buff , + hc_num, pdev->host.hc[hc_num].xfer_len); + } + } + return status; +} + + +/** +* @brief USB_OTG_HC_Halt : Halt channel +* @param pdev : Selected device +* @param hc_num : channel number +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_HC_Halt(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_HNPTXSTS_TypeDef nptxsts; + USB_OTG_HPTXSTS_TypeDef hptxsts; + USB_OTG_HCCHAR_TypeDef hcchar; + + nptxsts.d32 = 0; + hptxsts.d32 = 0; + hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); + hcchar.b.chen = 1; + hcchar.b.chdis = 1; + + /* Check for space in the request queue to issue the halt. */ + if (hcchar.b.eptype == HCCHAR_CTRL || hcchar.b.eptype == HCCHAR_BULK) + { + nptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); + if (nptxsts.b.nptxqspcavail == 0) + { + hcchar.b.chen = 0; + } + } + else + { + hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); + if (hptxsts.b.ptxqspcavail == 0) + { + hcchar.b.chen = 0; + } + } + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); + return status; +} + +/** +* @brief Issue a ping token +* @param None +* @retval : None +*/ +USB_OTG_STS USB_OTG_HC_DoPing(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_HCCHAR_TypeDef hcchar; + USB_OTG_HCTSIZn_TypeDef hctsiz; + + hctsiz.d32 = 0; + hctsiz.b.dopng = 1; + hctsiz.b.pktcnt = 1; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32); + + hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); + return status; +} + +/** +* @brief Stop the device and clean up fifo's +* @param None +* @retval : None +*/ +void USB_OTG_StopHost(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_HCCHAR_TypeDef hcchar; + uint32_t i; + + USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINTMSK , 0); + USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINT, 0xFFFFFFFF); + /* Flush out any leftover queued requests. */ + + for (i = 0; i < pdev->cfg.host_channels; i++) + { + hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[i]->HCCHAR); + hcchar.b.chen = 0; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[i]->HCCHAR, hcchar.d32); + } + + /* Flush the FIFO */ + USB_OTG_FlushRxFifo(pdev); + USB_OTG_FlushTxFifo(pdev , 0x10 ); +} +#endif +#ifdef USE_DEVICE_MODE +/* PCD Core Layer */ + +/** +* @brief USB_OTG_InitDevSpeed :Initializes the DevSpd field of DCFG register +* depending the PHY type and the enumeration speed of the device. +* @param pdev : Selected device +* @retval : None +*/ +void USB_OTG_InitDevSpeed(USB_OTG_CORE_HANDLE *pdev , uint8_t speed) +{ + USB_OTG_DCFG_TypeDef dcfg; + + dcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCFG); + dcfg.b.devspd = speed; + USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCFG, dcfg.d32); +} + + +/** +* @brief USB_OTG_CoreInitDev : Initializes the USB_OTG controller registers +* for device mode +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_CoreInitDev (USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + uint32_t i; + USB_OTG_DCFG_TypeDef dcfg; + USB_OTG_FSIZ_TypeDef nptxfifosize; + USB_OTG_FSIZ_TypeDef txfifosize; + USB_OTG_DIEPMSK_TypeDef msk; + USB_OTG_DTHRCTL_TypeDef dthrctl; + + depctl.d32 = 0; + dcfg.d32 = 0; + nptxfifosize.d32 = 0; + txfifosize.d32 = 0; + msk.d32 = 0; + + /* Restart the Phy Clock */ + USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, 0); + /* Device configuration register */ + dcfg.d32 = USB_OTG_READ_REG32( &pdev->regs.DREGS->DCFG); + dcfg.b.perfrint = DCFG_FRAME_INTERVAL_80; + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DCFG, dcfg.d32 ); + +#ifdef USB_OTG_FS_CORE + if(pdev->cfg.coreID == USB_OTG_FS_CORE_ID ) + { + + /* Set Full speed phy */ + USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_FULL); + + /* set Rx FIFO size */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_FS_SIZE); + + /* EP0 TX*/ + nptxfifosize.b.depth = TX0_FIFO_FS_SIZE; + nptxfifosize.b.startaddr = RX_FIFO_FS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32 ); + + + /* EP1 TX*/ + txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; + txfifosize.b.depth = TX1_FIFO_FS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[0], txfifosize.d32 ); + + + /* EP2 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX2_FIFO_FS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[1], txfifosize.d32 ); + + + /* EP3 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX3_FIFO_FS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[2], txfifosize.d32 ); + } +#endif +#ifdef USB_OTG_HS_CORE + if(pdev->cfg.coreID == USB_OTG_HS_CORE_ID ) + { + + /* Set High speed phy */ + + if(pdev->cfg.phy_itface == USB_OTG_ULPI_PHY) + { + USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_HIGH); + } + else /* set High speed phy in Full speed mode */ + { + USB_OTG_InitDevSpeed (pdev , USB_OTG_SPEED_PARAM_HIGH_IN_FULL); + } + + /* set Rx FIFO size */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRXFSIZ, RX_FIFO_HS_SIZE); + + /* EP0 TX*/ + nptxfifosize.b.depth = TX0_FIFO_HS_SIZE; + nptxfifosize.b.startaddr = RX_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF0_HNPTXFSIZ, nptxfifosize.d32 ); + + + /* EP1 TX*/ + txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; + txfifosize.b.depth = TX1_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[0], txfifosize.d32 ); + + + /* EP2 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX2_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[1], txfifosize.d32 ); + + + /* EP3 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX3_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[2], txfifosize.d32 ); + + /* EP4 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX4_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[3], txfifosize.d32 ); + + + /* EP5 TX*/ + txfifosize.b.startaddr += txfifosize.b.depth; + txfifosize.b.depth = TX5_FIFO_HS_SIZE; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->DIEPTXF[4], txfifosize.d32 ); + } +#endif + /* Flush the FIFOs */ + USB_OTG_FlushTxFifo(pdev , 0x10); /* all Tx FIFOs */ + USB_OTG_FlushRxFifo(pdev); + /* Clear all pending Device Interrupts */ + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, 0 ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, 0 ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINT, 0xFFFFFFFF ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, 0 ); + + for (i = 0; i < pdev->cfg.dev_endpoints; i++) + { + depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[i]->DIEPCTL); + if (depctl.b.epena) + { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } + else + { + depctl.d32 = 0; + } + USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPCTL, depctl.d32); + USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPTSIZ, 0); + USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPINT, 0xFF); + } + for (i = 0; i < pdev->cfg.dev_endpoints; i++) + { + USB_OTG_DEPCTL_TypeDef depctl; + depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[i]->DOEPCTL); + if (depctl.b.epena) + { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } + else + { + depctl.d32 = 0; + } + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPCTL, depctl.d32); + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPTSIZ, 0); + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFF); + } + msk.d32 = 0; + msk.b.txfifoundrn = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPMSK, msk.d32, msk.d32); + + if (pdev->cfg.dma_enable == 1) + { + dthrctl.d32 = 0; + dthrctl.b.non_iso_thr_en = 1; + dthrctl.b.iso_thr_en = 1; + dthrctl.b.tx_thr_len = 64; + dthrctl.b.rx_thr_en = 1; + dthrctl.b.rx_thr_len = 64; + USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DTHRCTL, dthrctl.d32); + } + USB_OTG_EnableDevInt(pdev); + return status; +} + + +/** +* @brief USB_OTG_EnableDevInt : Enables the Device mode interrupts +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EnableDevInt(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_GINTMSK_TypeDef intmsk; + + intmsk.d32 = 0; + + /* Disable all interrupts. */ + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTMSK, 0); + /* Clear any pending interrupts */ + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTSTS, 0xFFFFFFFF); + /* Enable the common interrupts */ + USB_OTG_EnableCommonInt(pdev); + + if (pdev->cfg.dma_enable == 0) + { + intmsk.b.rxstsqlvl = 1; + } + + /* Enable interrupts matching to the Device mode ONLY */ + intmsk.b.usbsuspend = 1; + intmsk.b.usbreset = 1; + intmsk.b.enumdone = 1; + intmsk.b.inepintr = 1; + intmsk.b.outepintr = 1; + intmsk.b.sofintr = 1; + + intmsk.b.incomplisoin = 1; + intmsk.b.incomplisoout = 1; +#ifdef VBUS_SENSING_ENABLED + intmsk.b.sessreqintr = 1; + intmsk.b.otgintr = 1; +#endif + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, intmsk.d32, intmsk.d32); + return status; +} + + +/** +* @brief USB_OTG_GetDeviceSpeed +* Get the device speed from the device status register +* @param None +* @retval status +*/ +enum USB_OTG_SPEED USB_OTG_GetDeviceSpeed (USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_DSTS_TypeDef dsts; + enum USB_OTG_SPEED speed = USB_SPEED_UNKNOWN; + + + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + + switch (dsts.b.enumspd) + { + case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: + speed = USB_SPEED_HIGH; + break; + case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: + case DSTS_ENUMSPD_FS_PHY_48MHZ: + speed = USB_SPEED_FULL; + break; + + case DSTS_ENUMSPD_LS_PHY_6MHZ: + speed = USB_SPEED_LOW; + break; + } + + return speed; +} +/** +* @brief enables EP0 OUT to receive SETUP packets and configures EP0 +* for transmitting packets +* @param None +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EP0Activate(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DSTS_TypeDef dsts; + USB_OTG_DEPCTL_TypeDef diepctl; + USB_OTG_DCTL_TypeDef dctl; + + dctl.d32 = 0; + /* Read the Device Status and Endpoint 0 Control registers */ + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + diepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL); + /* Set the MPS of the IN EP based on the enumeration speed */ + switch (dsts.b.enumspd) + { + case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: + case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: + case DSTS_ENUMSPD_FS_PHY_48MHZ: + diepctl.b.mps = DEP0CTL_MPS_64; + break; + case DSTS_ENUMSPD_LS_PHY_6MHZ: + diepctl.b.mps = DEP0CTL_MPS_8; + break; + } + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[0]->DIEPCTL, diepctl.d32); + dctl.b.cgnpinnak = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, dctl.d32); + return status; +} + + +/** +* @brief USB_OTG_EPActivate : Activates an EP +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EPActivate(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + USB_OTG_DAINT_TypeDef daintmsk; + __IO uint32_t *addr; + + + depctl.d32 = 0; + daintmsk.d32 = 0; + /* Read DEPCTLn register */ + if (ep->is_in == 1) + { + addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; + daintmsk.ep.in = 1 << ep->num; + } + else + { + addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; + daintmsk.ep.out = 1 << ep->num; + } + /* If the EP is already active don't change the EP Control + * register. */ + depctl.d32 = USB_OTG_READ_REG32(addr); + if (!depctl.b.usbactep) + { + depctl.b.mps = ep->maxpacket; + depctl.b.eptype = ep->type; + depctl.b.txfnum = ep->tx_fifo_num; + depctl.b.setd0pid = 1; + depctl.b.usbactep = 1; + USB_OTG_WRITE_REG32(addr, depctl.d32); + } + /* Enable the Interrupt for this EP */ +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED + if((ep->num == 1)&&(pdev->cfg.coreID == USB_OTG_HS_CORE_ID)) + { + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DEACHMSK, 0, daintmsk.d32); + } + else +#endif + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, 0, daintmsk.d32); + return status; +} + + +/** +* @brief USB_OTG_EPDeactivate : Deactivates an EP +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EPDeactivate(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + USB_OTG_DAINT_TypeDef daintmsk; + __IO uint32_t *addr; + + depctl.d32 = 0; + daintmsk.d32 = 0; + /* Read DEPCTLn register */ + if (ep->is_in == 1) + { + addr = &pdev->regs.INEP_REGS[ep->num]->DIEPCTL; + daintmsk.ep.in = 1 << ep->num; + } + else + { + addr = &pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL; + daintmsk.ep.out = 1 << ep->num; + } + depctl.b.usbactep = 0; + USB_OTG_WRITE_REG32(addr, depctl.d32); + /* Disable the Interrupt for this EP */ + +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED + if((ep->num == 1)&&(pdev->cfg.coreID == USB_OTG_HS_CORE_ID)) + { + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DEACHMSK, daintmsk.d32, 0); + } + else +#endif + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DAINTMSK, daintmsk.d32, 0); + return status; +} + + +/** +* @brief USB_OTG_EPStartXfer : Handle the setup for data xfer for an EP and +* starts the xfer +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EPStartXfer(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + USB_OTG_DEPXFRSIZ_TypeDef deptsiz; + USB_OTG_DSTS_TypeDef dsts; + uint32_t fifoemptymsk = 0; + + depctl.d32 = 0; + deptsiz.d32 = 0; + /* IN endpoint */ + if (ep->is_in == 1) + { + depctl.d32 = USB_OTG_READ_REG32(&(pdev->regs.INEP_REGS[ep->num]->DIEPCTL)); + deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ)); + /* Zero Length Packet? */ + if (ep->xfer_len == 0) + { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + } + else + { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + deptsiz.b.xfersize = ep->xfer_len; + deptsiz.b.pktcnt = (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; + + if (ep->type == EP_TYPE_ISOC) + { + deptsiz.b.mc = 1; + } + } + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ, deptsiz.d32); + + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPDMA, ep->dma_addr); + } + else + { + if (ep->type != EP_TYPE_ISOC) + { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) + { + fifoemptymsk = 1 << ep->num; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, 0, fifoemptymsk); + } + } + } + + + if (ep->type == EP_TYPE_ISOC) + { + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + + if (((dsts.b.soffn)&0x1) == 0) + { + depctl.b.setd1pid = 1; + } + else + { + depctl.b.setd0pid = 1; + } + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPCTL, depctl.d32); + + if (ep->type == EP_TYPE_ISOC) + { + USB_OTG_WritePacket(pdev, ep->xfer_buff, ep->num, ep->xfer_len); + } + } + else + { + /* OUT endpoint */ + depctl.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL)); + deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ)); + /* Program the transfer size and packet count as follows: + * pktcnt = N + * xfersize = N * maxpacket + */ + if (ep->xfer_len == 0) + { + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + } + else + { + deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; + } + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ, deptsiz.d32); + + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPDMA, ep->dma_addr); + } + + if (ep->type == EP_TYPE_ISOC) + { + if (ep->even_odd_frame) + { + depctl.b.setd1pid = 1; + } + else + { + depctl.b.setd0pid = 1; + } + } + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL, depctl.d32); + } + return status; +} + + +/** +* @brief USB_OTG_EP0StartXfer : Handle the setup for a data xfer for EP0 and +* starts the xfer +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EP0StartXfer(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + USB_OTG_DEP0XFRSIZ_TypeDef deptsiz; + USB_OTG_INEPREGS *in_regs; + uint32_t fifoemptymsk = 0; + + depctl.d32 = 0; + deptsiz.d32 = 0; + /* IN endpoint */ + if (ep->is_in == 1) + { + in_regs = pdev->regs.INEP_REGS[0]; + depctl.d32 = USB_OTG_READ_REG32(&in_regs->DIEPCTL); + deptsiz.d32 = USB_OTG_READ_REG32(&in_regs->DIEPTSIZ); + /* Zero Length Packet? */ + if (ep->xfer_len == 0) + { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + + } + else + { + if (ep->xfer_len > ep->maxpacket) + { + ep->xfer_len = ep->maxpacket; + deptsiz.b.xfersize = ep->maxpacket; + } + else + { + deptsiz.b.xfersize = ep->xfer_len; + } + deptsiz.b.pktcnt = 1; + } + USB_OTG_WRITE_REG32(&in_regs->DIEPTSIZ, deptsiz.d32); + + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPDMA, ep->dma_addr); + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + USB_OTG_WRITE_REG32(&in_regs->DIEPCTL, depctl.d32); + + + + if (pdev->cfg.dma_enable == 0) + { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) + { + { + fifoemptymsk |= 1 << ep->num; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, 0, fifoemptymsk); + } + } + } + } + else + { + /* OUT endpoint */ + depctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); + deptsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ); + /* Program the transfer size and packet count as follows: + * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) + * pktcnt = N */ + if (ep->xfer_len == 0) + { + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + } + else + { + ep->xfer_len = ep->maxpacket; + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + } + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPTSIZ, deptsiz.d32); + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[ep->num]->DOEPDMA, ep->dma_addr); + } + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + USB_OTG_WRITE_REG32 (&(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL), depctl.d32); + + } + return status; +} + + +/** +* @brief USB_OTG_EPSetStall : Set the EP STALL +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EPSetStall(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + __IO uint32_t *depctl_addr; + + depctl.d32 = 0; + if (ep->is_in == 1) + { + depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + /* set the disable and stall bits */ + if (depctl.b.epena) + { + depctl.b.epdis = 1; + } + depctl.b.stall = 1; + USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); + } + else + { + depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + /* set the stall bit */ + depctl.b.stall = 1; + USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); + } + return status; +} + + +/** +* @brief Clear the EP STALL +* @param pdev : Selected device +* @retval USB_OTG_STS : status +*/ +USB_OTG_STS USB_OTG_EPClearStall(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep) +{ + USB_OTG_STS status = USB_OTG_OK; + USB_OTG_DEPCTL_TypeDef depctl; + __IO uint32_t *depctl_addr; + + depctl.d32 = 0; + + if (ep->is_in == 1) + { + depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); + } + else + { + depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); + } + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + /* clear the stall bits */ + depctl.b.stall = 0; + if (ep->type == EP_TYPE_INTR || ep->type == EP_TYPE_BULK) + { + depctl.b.setd0pid = 1; /* DATA0 */ + } + USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); + return status; +} + + +/** +* @brief USB_OTG_ReadDevAllOutEp_itr : returns OUT endpoint interrupt bits +* @param pdev : Selected device +* @retval OUT endpoint interrupt bits +*/ +uint32_t USB_OTG_ReadDevAllOutEp_itr(USB_OTG_CORE_HANDLE *pdev) +{ + uint32_t v; + v = USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINT); + v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINTMSK); + return ((v & 0xffff0000) >> 16); +} + + +/** +* @brief USB_OTG_ReadDevOutEP_itr : returns Device OUT EP Interrupt register +* @param pdev : Selected device +* @param ep : end point number +* @retval Device OUT EP Interrupt register +*/ +uint32_t USB_OTG_ReadDevOutEP_itr(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) +{ + uint32_t v; + v = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[epnum]->DOEPINT); + v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DOEPMSK); + return v; +} + + +/** +* @brief USB_OTG_ReadDevAllInEPItr : Get int status register +* @param pdev : Selected device +* @retval int status register +*/ +uint32_t USB_OTG_ReadDevAllInEPItr(USB_OTG_CORE_HANDLE *pdev) +{ + uint32_t v; + v = USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINT); + v &= USB_OTG_READ_REG32(&pdev->regs.DREGS->DAINTMSK); + return (v & 0xffff); +} + +/** +* @brief configures EPO to receive SETUP packets +* @param None +* @retval : None +*/ +void USB_OTG_EP0_OutStart(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_DEP0XFRSIZ_TypeDef doeptsize0; + doeptsize0.d32 = 0; + doeptsize0.b.supcnt = 3; + doeptsize0.b.pktcnt = 1; + doeptsize0.b.xfersize = 8 * 3; + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPTSIZ, doeptsize0.d32 ); + + if (pdev->cfg.dma_enable == 1) + { + USB_OTG_DEPCTL_TypeDef doepctl; + doepctl.d32 = 0; + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPDMA, + (uint32_t)&pdev->dev.setup_packet); + + /* EP enable */ + doepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPCTL); + doepctl.b.epena = 1; + doepctl.d32 = 0x80008000; + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[0]->DOEPCTL, doepctl.d32); + } +} + +/** +* @brief USB_OTG_RemoteWakeup : active remote wakeup signalling +* @param None +* @retval : None +*/ +void USB_OTG_ActiveRemoteWakeup(USB_OTG_CORE_HANDLE *pdev) +{ + + USB_OTG_DCTL_TypeDef dctl; + USB_OTG_DSTS_TypeDef dsts; + USB_OTG_PCGCCTL_TypeDef power; + + if (pdev->dev.DevRemoteWakeup) + { + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + if(dsts.b.suspsts == 1) + { + if(pdev->cfg.low_power) + { + /* un-gate USB Core clock */ + power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); + power.b.gatehclk = 0; + power.b.stoppclk = 0; + USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); + } + /* active Remote wakeup signaling */ + dctl.d32 = 0; + dctl.b.rmtwkupsig = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, 0, dctl.d32); + USB_OTG_BSP_mDelay(5); + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, 0 ); + } + } +} + + +/** +* @brief USB_OTG_UngateClock : active USB Core clock +* @param None +* @retval : None +*/ +void USB_OTG_UngateClock(USB_OTG_CORE_HANDLE *pdev) +{ + if(pdev->cfg.low_power) + { + + USB_OTG_DSTS_TypeDef dsts; + USB_OTG_PCGCCTL_TypeDef power; + + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + + if(dsts.b.suspsts == 1) + { + /* un-gate USB Core clock */ + power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); + power.b.gatehclk = 0; + power.b.stoppclk = 0; + USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); + + } + } +} + +/** +* @brief Stop the device and clean up fifo's +* @param None +* @retval : None +*/ +void USB_OTG_StopDevice(USB_OTG_CORE_HANDLE *pdev) +{ + uint32_t i; + + pdev->dev.device_status = 1; + + for (i = 0; i < pdev->cfg.dev_endpoints ; i++) + { + USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPINT, 0xFF); + USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFF); + } + + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, 0 ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, 0 ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, 0 ); + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINT, 0xFFFFFFFF ); + + /* Flush the FIFO */ + USB_OTG_FlushRxFifo(pdev); + USB_OTG_FlushTxFifo(pdev , 0x10 ); +} + +/** +* @brief returns the EP Status +* @param pdev : Selected device +* ep : endpoint structure +* @retval : EP status +*/ + +uint32_t USB_OTG_GetEPStatus(USB_OTG_CORE_HANDLE *pdev ,USB_OTG_EP *ep) +{ + USB_OTG_DEPCTL_TypeDef depctl; + __IO uint32_t *depctl_addr; + uint32_t Status = 0; + + depctl.d32 = 0; + if (ep->is_in == 1) + { + depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + + if (depctl.b.stall == 1) + Status = USB_OTG_EP_TX_STALL; + else if (depctl.b.naksts == 1) + Status = USB_OTG_EP_TX_NAK; + else + Status = USB_OTG_EP_TX_VALID; + + } + else + { + depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + if (depctl.b.stall == 1) + Status = USB_OTG_EP_RX_STALL; + else if (depctl.b.naksts == 1) + Status = USB_OTG_EP_RX_NAK; + else + Status = USB_OTG_EP_RX_VALID; + } + + /* Return the current status */ + return Status; +} + +/** +* @brief Set the EP Status +* @param pdev : Selected device +* Status : new Status +* ep : EP structure +* @retval : None +*/ +void USB_OTG_SetEPStatus (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep , uint32_t Status) +{ + USB_OTG_DEPCTL_TypeDef depctl; + __IO uint32_t *depctl_addr; + + depctl.d32 = 0; + + /* Process for IN endpoint */ + if (ep->is_in == 1) + { + depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + + if (Status == USB_OTG_EP_TX_STALL) + { + USB_OTG_EPSetStall(pdev, ep); return; + } + else if (Status == USB_OTG_EP_TX_NAK) + depctl.b.snak = 1; + else if (Status == USB_OTG_EP_TX_VALID) + { + if (depctl.b.stall == 1) + { + ep->even_odd_frame = 0; + USB_OTG_EPClearStall(pdev, ep); + return; + } + depctl.b.cnak = 1; + depctl.b.usbactep = 1; + depctl.b.epena = 1; + } + else if (Status == USB_OTG_EP_TX_DIS) + depctl.b.usbactep = 0; + } + else /* Process for OUT endpoint */ + { + depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); + depctl.d32 = USB_OTG_READ_REG32(depctl_addr); + + if (Status == USB_OTG_EP_RX_STALL) { + depctl.b.stall = 1; + } + else if (Status == USB_OTG_EP_RX_NAK) + depctl.b.snak = 1; + else if (Status == USB_OTG_EP_RX_VALID) + { + if (depctl.b.stall == 1) + { + ep->even_odd_frame = 0; + USB_OTG_EPClearStall(pdev, ep); + return; + } + depctl.b.cnak = 1; + depctl.b.usbactep = 1; + depctl.b.epena = 1; + } + else if (Status == USB_OTG_EP_RX_DIS) + { + depctl.b.usbactep = 0; + } + } + + USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); +} + +#endif +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/usb_core.h b/example/stm32f4/Projects/discovery_demo/usb_core.h new file mode 100644 index 0000000..82a09e1 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usb_core.h @@ -0,0 +1,408 @@ +/** + ****************************************************************************** + * @file usb_core.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Header of the Core Layer + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CORE_H__ +#define __USB_CORE_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" +#include "usb_regs.h" +#include "usb_defines.h" + + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_CORE + * @brief usb otg driver core layer + * @{ + */ + + +/** @defgroup USB_CORE_Exported_Defines + * @{ + */ + +#define USB_OTG_EP0_IDLE 0 +#define USB_OTG_EP0_SETUP 1 +#define USB_OTG_EP0_DATA_IN 2 +#define USB_OTG_EP0_DATA_OUT 3 +#define USB_OTG_EP0_STATUS_IN 4 +#define USB_OTG_EP0_STATUS_OUT 5 +#define USB_OTG_EP0_STALL 6 + +#define USB_OTG_EP_TX_DIS 0x0000 +#define USB_OTG_EP_TX_STALL 0x0010 +#define USB_OTG_EP_TX_NAK 0x0020 +#define USB_OTG_EP_TX_VALID 0x0030 + +#define USB_OTG_EP_RX_DIS 0x0000 +#define USB_OTG_EP_RX_STALL 0x1000 +#define USB_OTG_EP_RX_NAK 0x2000 +#define USB_OTG_EP_RX_VALID 0x3000 +/** + * @} + */ +#define MAX_DATA_LENGTH 0xFF + +/** @defgroup USB_CORE_Exported_Types + * @{ + */ + + +typedef enum { + USB_OTG_OK = 0, + USB_OTG_FAIL +}USB_OTG_STS; + +typedef enum { + HC_IDLE = 0, + HC_XFRC, + HC_HALTED, + HC_NAK, + HC_NYET, + HC_STALL, + HC_XACTERR, + HC_BBLERR, + HC_DATATGLERR, +}HC_STATUS; + +typedef enum { + URB_IDLE = 0, + URB_DONE, + URB_NOTREADY, + URB_ERROR, + URB_STALL +}URB_STATE; + +typedef enum { + CTRL_START = 0, + CTRL_XFRC, + CTRL_HALTED, + CTRL_NAK, + CTRL_STALL, + CTRL_XACTERR, + CTRL_BBLERR, + CTRL_DATATGLERR, + CTRL_FAIL +}CTRL_STATUS; + + +typedef struct USB_OTG_hc +{ + uint8_t dev_addr ; + uint8_t ep_num; + uint8_t ep_is_in; + uint8_t speed; + uint8_t do_ping; + uint8_t ep_type; + uint16_t max_packet; + uint8_t data_pid; + uint8_t *xfer_buff; + uint32_t xfer_len; + uint32_t xfer_count; + uint8_t toggle_in; + uint8_t toggle_out; + uint32_t dma_addr; +} +USB_OTG_HC , *PUSB_OTG_HC; + +typedef struct USB_OTG_ep +{ + uint8_t num; + uint8_t is_in; + uint8_t is_stall; + uint8_t type; + uint8_t data_pid_start; + uint8_t even_odd_frame; + uint16_t tx_fifo_num; + uint32_t maxpacket; + /* transaction level variables*/ + uint8_t *xfer_buff; + uint32_t dma_addr; + uint32_t xfer_len; + uint32_t xfer_count; + /* Transfer level variables*/ + uint32_t rem_data_len; + uint32_t total_data_len; + uint32_t ctl_data_len; + +} + +USB_OTG_EP , *PUSB_OTG_EP; + + + +typedef struct USB_OTG_core_cfg +{ + uint8_t host_channels; + uint8_t dev_endpoints; + uint8_t speed; + uint8_t dma_enable; + uint16_t mps; + uint16_t TotalFifoSize; + uint8_t phy_itface; + uint8_t Sof_output; + uint8_t low_power; + uint8_t coreID; + +} +USB_OTG_CORE_CFGS, *PUSB_OTG_CORE_CFGS; + + + +typedef struct usb_setup_req { + + uint8_t bmRequest; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} USB_SETUP_REQ; + +typedef struct _Device_TypeDef +{ + uint8_t *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetLangIDStrDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetManufacturerStrDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetProductStrDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetSerialStrDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetConfigurationStrDescriptor)( uint8_t speed , uint16_t *length); + uint8_t *(*GetInterfaceStrDescriptor)( uint8_t speed , uint16_t *length); +} USBD_DEVICE, *pUSBD_DEVICE; + +typedef struct USB_OTG_hPort +{ + void (*Disconnect) (void *phost); + void (*Connect) (void *phost); + uint8_t ConnStatus; + uint8_t DisconnStatus; + uint8_t ConnHandled; + uint8_t DisconnHandled; +} USB_OTG_hPort_TypeDef; + +typedef struct _Device_cb +{ + uint8_t (*Init) (void *pdev , uint8_t cfgidx); + uint8_t (*DeInit) (void *pdev , uint8_t cfgidx); + /* Control Endpoints*/ + uint8_t (*Setup) (void *pdev , USB_SETUP_REQ *req); + uint8_t (*EP0_TxSent) (void *pdev ); + uint8_t (*EP0_RxReady) (void *pdev ); + /* Class Specific Endpoints*/ + uint8_t (*DataIn) (void *pdev , uint8_t epnum); + uint8_t (*DataOut) (void *pdev , uint8_t epnum); + uint8_t (*SOF) (void *pdev); + uint8_t (*IsoINIncomplete) (void *pdev); + uint8_t (*IsoOUTIncomplete) (void *pdev); + + uint8_t *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length); +#ifdef USB_OTG_HS_CORE + uint8_t *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length); +#endif + +#ifdef USB_SUPPORT_USER_STRING_DESC + uint8_t *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index, uint16_t *length); +#endif + +} USBD_Class_cb_TypeDef; + + + +typedef struct _USBD_USR_PROP +{ + void (*Init)(void); + void (*DeviceReset)(uint8_t speed); + void (*DeviceConfigured)(void); + void (*DeviceSuspended)(void); + void (*DeviceResumed)(void); + + void (*DeviceConnected)(void); + void (*DeviceDisconnected)(void); + +} +USBD_Usr_cb_TypeDef; + +typedef struct _DCD +{ + uint8_t device_config; + uint8_t device_state; + uint8_t device_status; + uint8_t device_address; + uint32_t DevRemoteWakeup; + USB_OTG_EP in_ep [USB_OTG_MAX_TX_FIFOS]; + USB_OTG_EP out_ep [USB_OTG_MAX_TX_FIFOS]; + uint8_t setup_packet [8*3]; + USBD_Class_cb_TypeDef *class_cb; + USBD_Usr_cb_TypeDef *usr_cb; + USBD_DEVICE *usr_device; + uint8_t *pConfig_descriptor; + } +DCD_DEV , *DCD_PDEV; + + +typedef struct _HCD +{ + uint8_t Rx_Buffer [MAX_DATA_LENGTH]; + __IO uint32_t ConnSts; + __IO uint32_t ErrCnt[USB_OTG_MAX_TX_FIFOS]; + __IO uint32_t XferCnt[USB_OTG_MAX_TX_FIFOS]; + __IO HC_STATUS HC_Status[USB_OTG_MAX_TX_FIFOS]; + __IO URB_STATE URB_State[USB_OTG_MAX_TX_FIFOS]; + USB_OTG_HC hc [USB_OTG_MAX_TX_FIFOS]; + uint16_t channel [USB_OTG_MAX_TX_FIFOS]; + USB_OTG_hPort_TypeDef *port_cb; +} +HCD_DEV , *USB_OTG_USBH_PDEV; + + +typedef struct _OTG +{ + uint8_t OTG_State; + uint8_t OTG_PrevState; + uint8_t OTG_Mode; +} +OTG_DEV , *USB_OTG_USBO_PDEV; + +typedef struct USB_OTG_handle +{ + USB_OTG_CORE_CFGS cfg; + USB_OTG_CORE_REGS regs; +#ifdef USE_DEVICE_MODE + DCD_DEV dev; +#endif +#ifdef USE_HOST_MODE + HCD_DEV host; +#endif +#ifdef USE_OTG_MODE + OTG_DEV otg; +#endif +} +USB_OTG_CORE_HANDLE , *PUSB_OTG_CORE_HANDLE; + +/** + * @} + */ + + +/** @defgroup USB_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USB_CORE_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_CORE_Exported_FunctionsPrototype + * @{ + */ + + +USB_OTG_STS USB_OTG_CoreInit (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_SelectCore (USB_OTG_CORE_HANDLE *pdev, + USB_OTG_CORE_ID_TypeDef coreID); +USB_OTG_STS USB_OTG_EnableGlobalInt (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_DisableGlobalInt(USB_OTG_CORE_HANDLE *pdev); +void* USB_OTG_ReadPacket (USB_OTG_CORE_HANDLE *pdev , + uint8_t *dest, + uint16_t len); +USB_OTG_STS USB_OTG_WritePacket (USB_OTG_CORE_HANDLE *pdev , + uint8_t *src, + uint8_t ch_ep_num, + uint16_t len); +USB_OTG_STS USB_OTG_FlushTxFifo (USB_OTG_CORE_HANDLE *pdev , uint32_t num); +USB_OTG_STS USB_OTG_FlushRxFifo (USB_OTG_CORE_HANDLE *pdev); + +uint32_t USB_OTG_ReadCoreItr (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_ReadOtgItr (USB_OTG_CORE_HANDLE *pdev); +uint8_t USB_OTG_IsHostMode (USB_OTG_CORE_HANDLE *pdev); +uint8_t USB_OTG_IsDeviceMode (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_GetMode (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_PhyInit (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_SetCurrentMode (USB_OTG_CORE_HANDLE *pdev, + uint8_t mode); + +/*********************** HOST APIs ********************************************/ +#ifdef USE_HOST_MODE +USB_OTG_STS USB_OTG_CoreInitHost (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_EnableHostInt (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_HC_Init (USB_OTG_CORE_HANDLE *pdev, uint8_t hc_num); +USB_OTG_STS USB_OTG_HC_Halt (USB_OTG_CORE_HANDLE *pdev, uint8_t hc_num); +USB_OTG_STS USB_OTG_HC_StartXfer (USB_OTG_CORE_HANDLE *pdev, uint8_t hc_num); +USB_OTG_STS USB_OTG_HC_DoPing (USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num); +uint32_t USB_OTG_ReadHostAllChannels_intr (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_ResetPort (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_ReadHPRT0 (USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_DriveVbus (USB_OTG_CORE_HANDLE *pdev, uint8_t state); +void USB_OTG_InitFSLSPClkSel (USB_OTG_CORE_HANDLE *pdev ,uint8_t freq); +uint8_t USB_OTG_IsEvenFrame (USB_OTG_CORE_HANDLE *pdev) ; +void USB_OTG_StopHost (USB_OTG_CORE_HANDLE *pdev); +#endif +/********************* DEVICE APIs ********************************************/ +#ifdef USE_DEVICE_MODE +USB_OTG_STS USB_OTG_CoreInitDev (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_EnableDevInt (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_ReadDevAllInEPItr (USB_OTG_CORE_HANDLE *pdev); +enum USB_OTG_SPEED USB_OTG_GetDeviceSpeed (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_EP0Activate (USB_OTG_CORE_HANDLE *pdev); +USB_OTG_STS USB_OTG_EPActivate (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +USB_OTG_STS USB_OTG_EPDeactivate(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +USB_OTG_STS USB_OTG_EPStartXfer (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +USB_OTG_STS USB_OTG_EP0StartXfer(USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +USB_OTG_STS USB_OTG_EPSetStall (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +USB_OTG_STS USB_OTG_EPClearStall (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep); +uint32_t USB_OTG_ReadDevAllOutEp_itr (USB_OTG_CORE_HANDLE *pdev); +uint32_t USB_OTG_ReadDevOutEP_itr (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); +uint32_t USB_OTG_ReadDevAllInEPItr (USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_InitDevSpeed (USB_OTG_CORE_HANDLE *pdev , uint8_t speed); +uint8_t USBH_IsEvenFrame (USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_EP0_OutStart(USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_ActiveRemoteWakeup(USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_UngateClock(USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_StopDevice(USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_SetEPStatus (USB_OTG_CORE_HANDLE *pdev , USB_OTG_EP *ep , uint32_t Status); +uint32_t USB_OTG_GetEPStatus(USB_OTG_CORE_HANDLE *pdev ,USB_OTG_EP *ep); +#endif +/** + * @} + */ + +#endif /* __USB_CORE_H__ */ + + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/example/stm32f4/Projects/discovery_demo/usbd_conf.h b/example/stm32f4/Projects/discovery_demo/usbd_conf.h new file mode 100644 index 0000000..3ff02b6 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usbd_conf.h @@ -0,0 +1,93 @@ +/** + ****************************************************************************** + * @file usbd_conf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief USB Device configuration file + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CONF__H__ +#define __USBD_CONF__H__ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4_discovery.h" + +/** @defgroup USB_CONF_Exported_Defines + * @{ + */ + + +#define USBD_CFG_MAX_NUM 1 +#define USBD_ITF_MAX_NUM 1 + +#define USB_MAX_STR_DESC_SIZ 64 + + + +#define USBD_DYNAMIC_DESCRIPTOR_CHANGE_ENABLED + +/** @defgroup USB_String_Descriptors + * @{ + */ + + +/** @defgroup USB_HID_Class_Layer_Parameter + * @{ + */ +#define HID_IN_EP 0x81 +#define HID_OUT_EP 0x01 + +#define HID_IN_PACKET 4 +#define HID_OUT_PACKET 4 + +/** + * @} + */ +/** @defgroup USB_CONF_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USB_CONF_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_CONF_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_CONF_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + + +#endif //__USBD_CONF__H__ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/example/stm32f4/Projects/discovery_demo/usbd_desc.c b/example/stm32f4/Projects/discovery_demo/usbd_desc.c new file mode 100644 index 0000000..ff9b670 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usbd_desc.c @@ -0,0 +1,313 @@ +/** + ****************************************************************************** + * @file usbd_desc.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file provides the USBD descriptors and string formating method. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_req.h" +#include "usbd_conf.h" +#include "usb_regs.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_DESC + * @brief USBD descriptors module + * @{ + */ + +/** @defgroup USBD_DESC_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_DESC_Private_Defines + * @{ + */ + +#define USBD_VID 0x0483 +#define USBD_PID 0x5710 + +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "STMicroelectronics" + +#define USBD_PRODUCT_HS_STRING "Joystick in HS mode" +#define USBD_SERIALNUMBER_HS_STRING "00000000011B" + +#define USBD_PRODUCT_FS_STRING "Joystick in FS Mode" +#define USBD_SERIALNUMBER_FS_STRING "00000000011C" + +#define USBD_CONFIGURATION_HS_STRING "HID Config" +#define USBD_INTERFACE_HS_STRING "HID Interface" + +#define USBD_CONFIGURATION_FS_STRING "HID Config" +#define USBD_INTERFACE_FS_STRING "HID Interface" +/** + * @} + */ + + +/** @defgroup USBD_DESC_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_DESC_Private_Variables + * @{ + */ + +USBD_DEVICE USR_desc = +{ + USBD_USR_DeviceDescriptor, + USBD_USR_LangIDStrDescriptor, + USBD_USR_ManufacturerStrDescriptor, + USBD_USR_ProductStrDescriptor, + USBD_USR_SerialStrDescriptor, + USBD_USR_ConfigStrDescriptor, + USBD_USR_InterfaceStrDescriptor, + +}; + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 + #endif +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ +/* USB Standard Device Descriptor */ +__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END = + { + 0x12, /*bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/ + 0x00, /*bcdUSB */ + 0x02, + 0x00, /*bDeviceClass*/ + 0x00, /*bDeviceSubClass*/ + 0x00, /*bDeviceProtocol*/ + USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/ + LOBYTE(USBD_VID), /*idVendor*/ + HIBYTE(USBD_VID), /*idVendor*/ + LOBYTE(USBD_PID), /*idVendor*/ + HIBYTE(USBD_PID), /*idVendor*/ + 0x00, /*bcdDevice rel. 2.00*/ + 0x02, + USBD_IDX_MFC_STR, /*Index of manufacturer string*/ + USBD_IDX_PRODUCT_STR, /*Index of product string*/ + USBD_IDX_SERIAL_STR, /*Index of serial number string*/ + USBD_CFG_MAX_NUM /*bNumConfigurations*/ + } ; /* USB_DeviceDescriptor */ + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 + #endif +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ +/* USB Standard Device Descriptor */ +__ALIGN_BEGIN uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = +{ + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +}; + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 + #endif +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ +/* USB Standard Device Descriptor */ +__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID] __ALIGN_END = +{ + USB_SIZ_STRING_LANGID, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; +/** + * @} + */ + + +/** @defgroup USBD_DESC_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_DESC_Private_Functions + * @{ + */ + +/** +* @brief USBD_USR_DeviceDescriptor +* return the device descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length) +{ + *length = sizeof(USBD_DeviceDesc); + return USBD_DeviceDesc; +} + +/** +* @brief USBD_USR_LangIDStrDescriptor +* return the LangID string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length) +{ + *length = sizeof(USBD_LangIDDesc); + return USBD_LangIDDesc; +} + + +/** +* @brief USBD_USR_ProductStrDescriptor +* return the product string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_ProductStrDescriptor( uint8_t speed , uint16_t *length) +{ + + + if(speed == 0) + { + USBD_GetString (USBD_PRODUCT_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString (USBD_PRODUCT_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** +* @brief USBD_USR_ManufacturerStrDescriptor +* return the manufacturer string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_ManufacturerStrDescriptor( uint8_t speed , uint16_t *length) +{ + USBD_GetString (USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + return USBD_StrDesc; +} + +/** +* @brief USBD_USR_SerialStrDescriptor +* return the serial number string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length) +{ + if(speed == USB_OTG_SPEED_HIGH) + { + USBD_GetString (USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString (USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** +* @brief USBD_USR_ConfigStrDescriptor +* return the configuration string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length) +{ + if(speed == USB_OTG_SPEED_HIGH) + { + USBD_GetString (USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString (USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + + +/** +* @brief USBD_USR_InterfaceStrDescriptor +* return the interface string descriptor +* @param speed : current device speed +* @param length : pointer to data length variable +* @retval pointer to descriptor buffer +*/ +uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length) +{ + if(speed == 0) + { + USBD_GetString (USBD_INTERFACE_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString (USBD_INTERFACE_FS_STRING, USBD_StrDesc, length); + } + return USBD_StrDesc; +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/example/stm32f4/Projects/discovery_demo/usbd_desc.h b/example/stm32f4/Projects/discovery_demo/usbd_desc.h new file mode 100644 index 0000000..ed999dc --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usbd_desc.h @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file usbd_desc.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief header file for the usbd_desc.c file + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USB_DESC_H +#define __USB_DESC_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_DESC + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_DESC_Exported_Defines + * @{ + */ +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 +#define USB_SIZ_DEVICE_DESC 18 +#define USB_SIZ_STRING_LANGID 4 + +/** + * @} + */ + + +/** @defgroup USBD_DESC_Exported_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_DESC_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_Variables + * @{ + */ +extern uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC]; +extern uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ]; +extern uint8_t USBD_OtherSpeedCfgDesc[USB_LEN_CFG_DESC]; +extern uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]; +extern uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID]; +extern USBD_DEVICE USR_desc; +/** + * @} + */ + +/** @defgroup USBD_DESC_Exported_FunctionsPrototype + * @{ + */ + + +uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_ManufacturerStrDescriptor ( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_ProductStrDescriptor ( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length); +uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length); + +#ifdef USB_SUPPORT_USER_STRING_DESC +uint8_t * USBD_USR_USRStringDesc (uint8_t speed, uint8_t idx , uint16_t *length); +#endif /* USB_SUPPORT_USER_STRING_DESC */ + +/** + * @} + */ + +#endif /* __USBD_DESC_H */ + +/** + * @} + */ + +/** +* @} +*/ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Projects/discovery_demo/usbd_usr.c b/example/stm32f4/Projects/discovery_demo/usbd_usr.c new file mode 100644 index 0000000..6ebd157 --- /dev/null +++ b/example/stm32f4/Projects/discovery_demo/usbd_usr.c @@ -0,0 +1,238 @@ +/** + ****************************************************************************** + * @file usbd_usr.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file includes the user application layer + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_usr.h" +#include "usbd_ioreq.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY +* @{ +*/ + +/** @defgroup USBD_USR +* @brief This file includes the user application layer +* @{ +*/ + +/** @defgroup USBD_USR_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_USR_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_USR_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_USR_Private_Variables +* @{ +*/ + +USBD_Usr_cb_TypeDef USR_cb = +{ + USBD_USR_Init, + USBD_USR_DeviceReset, + USBD_USR_DeviceConfigured, + USBD_USR_DeviceSuspended, + USBD_USR_DeviceResumed, + + USBD_USR_DeviceConnected, + USBD_USR_DeviceDisconnected, + + +}; + + + +/** +* @} +*/ + +/** @defgroup USBD_USR_Private_Constants +* @{ +*/ + +/** +* @} +*/ + + + +/** @defgroup USBD_USR_Private_FunctionPrototypes +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_USR_Private_Functions +* @{ +*/ + +/** +* @brief USBD_USR_Init +* Displays the message on LCD for host lib initialization +* @param None +* @retval None +*/ +void USBD_USR_Init(void) +{ + /* Setup SysTick Timer for 40 msec interrupts + This interrupt is used to probe the joystick */ + if (SysTick_Config(SystemCoreClock / 24)) + { + /* Capture error */ + while (1); + } +} + +/** +* @brief USBD_USR_DeviceReset +* Displays the message on LCD on device Reset Event +* @param speed : device speed +* @retval None +*/ +void USBD_USR_DeviceReset(uint8_t speed ) +{ + switch (speed) + { + case USB_OTG_SPEED_HIGH: + break; + + case USB_OTG_SPEED_FULL: + break; + default: + break; + + } +} + + +/** +* @brief USBD_USR_DeviceConfigured +* Displays the message on LCD on device configuration Event +* @param None +* @retval Staus +*/ +void USBD_USR_DeviceConfigured (void) +{ +} + + +/** +* @brief USBD_USR_DeviceConnected +* Displays the message on LCD on device connection Event +* @param None +* @retval Staus +*/ +void USBD_USR_DeviceConnected (void) +{ +} + + +/** +* @brief USBD_USR_DeviceDisonnected +* Displays the message on LCD on device disconnection Event +* @param None +* @retval Staus +*/ +void USBD_USR_DeviceDisconnected (void) +{ +} + +/** +* @brief USBD_USR_DeviceSuspended +* Displays the message on LCD on device suspend Event +* @param None +* @retval None +*/ +void USBD_USR_DeviceSuspended(void) +{ + /* Users can do their application actions here for the USB-Reset */ +} + + +/** +* @brief USBD_USR_DeviceResumed +* Displays the message on LCD on device resume Event +* @param None +* @retval None +*/ +void USBD_USR_DeviceResumed(void) +{ + /* Users can do their application actions here for the USB-Reset */ +} + +/** +* @} +*/ + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.47.2