diff options
| author | Author Name <[email protected]> | 2023-07-07 12:20:59 +0930 |
|---|---|---|
| committer | David Rowe <[email protected]> | 2023-07-07 12:29:06 +0930 |
| commit | ac7c48b4dee99d4c772f133d70d8d1b38262fcd2 (patch) | |
| tree | a2d0ace57a9c0e2e5b611c4987f6fed1b38b81e7 /stm32 | |
shallow zip-file copy from codec2 e9d726bf20
Diffstat (limited to 'stm32')
137 files changed, 25784 insertions, 0 deletions
diff --git a/stm32/CMakeLists.txt b/stm32/CMakeLists.txt new file mode 100644 index 0000000..892914f --- /dev/null +++ b/stm32/CMakeLists.txt @@ -0,0 +1,311 @@ +# +# stm32f4 support for Codec2 +# +# CMake configuration contributed by Richard Shaw (KF5OIM) +# Please report questions, comments, problems, or patches to the freetel +# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2 +# +set(ARM_GCC_BIN "" CACHE STRING "Path to the bin directory of your arm-eabi-none-gcc (optional)") +project(stm32f4 C ASM) + +if(CMAKE_CROSSCOMPILING) + message(STATUS "We are cross compiling...") +else() + message(STATUS "Performing standard host build...") +endif() + +cmake_minimum_required(VERSION 2.8) + +include(cmake/gencodebooks.cmake) + +# +# Prevent in-source builds +# If an in-source build is attempted, you will still need to clean up a few +# files manually. +# +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) +if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not " + "allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a " + "separate build directory and run cmake from there.") +endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + +#include(cmake/STM32_Toolchain.cmake) + +################################################### + +set(FLOAT_TYPE "hard" CACHE STRING "Floating point: defaults to hard.") +set(CMAKE_TOOLCHAIN_FILE "../stm32/cmake/STM32_Toolchain.cmake" CACHE STRING "Toolchain defs") + +################################################### + +# +# Find the git hash if this is a working copy. +# +if(EXISTS ${CMAKE_SOURCE_DIR}/.git) + find_package(Git QUIET) + if(Git_FOUND) + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --always HEAD + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE FREEDV_HASH + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "freedv-gui current git hash: ${FREEDV_HASH}") + add_definitions(-DGIT_HASH="${FREEDV_HASH}") + else() + message(WARNING "Git not found. Can not determine current commit hash.") + add_definitions(-DGIT_HASH="Unknown") + endif() +else() + add_definitions(-DGIT_HASH="None") +endif() + +# Set default C flags. +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=gnu11 -mlittle-endian -mthumb -mthumb-interwork --specs=nano.specs -u_printf_float -mcpu=cortex-m4 -ffunction-sections -fdata-sections -O3") + +add_definitions(-DSTM32F40_41xxx -DCORTEX_M4 -D__EMBEDDED__) +add_definitions(-DFREEDV_MODE_EN_DEFAULT=0 -DFREEDV_MODE_1600_EN=1 -DFREEDV_MODE_700D_EN=1 -DFREEDV_MODE_700E_EN=1 -DCODEC2_MODE_EN_DEFAULT=0 -DCODEC2_MODE_1300_EN=1 -DCODEC2_MODE_700C_EN=1) + +if(FLOAT_TYPE STREQUAL "hard") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsingle-precision-constant -Wdouble-promotion -mfpu=fpv4-sp-d16 -mfloat-abi=hard -D__FPU_PRESENT=1 -D__FPU_USED=1") + #CFLAGS += -fsingle-precision-constant +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msoft-float") +endif() + +option(VERIFY_OPT "Enable this for dump files to help verify optimization" OFF) +if(VERIFY_OPT) + add_definitions(-DDUMP) +endif() + +# Set default build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + link_libraries(g m) +else() + link_libraries(c m) +endif() + +# Setup defaults that can't be set in the toolchain file +set(CMAKE_EXE_LINKER_FLAGS "-u_init -T${CMAKE_SOURCE_DIR}/stm32_flash.ld -Xlinker --gc-sections") +set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf") +set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp") + +# Check build flags + +message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) +message(STATUS "CMAKE_ASM_FLAGS: " ${CMAKE_ASM_FLAGS}) + +################################################### + +# STM32F4 Standard Peripheral Library + +include(cmake/STM32_Lib.cmake) + +################################################### + +# Macro for elf->bin +macro(elf2bin target) + add_custom_command(TARGET ${target} + POST_BUILD COMMAND ${CMAKE_OBJCOPY} -O binary ${target}.elf ${target}.bin && ${CMAKE_OBJCOPY} -O ihex ${target}.elf ${target}.hex + COMMENT "Creating binary for ${target}") + set_source_files_properties(${target}.bin PROPERTIES GENERATED TRUE) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES ${target}.bin ${target}.hex) +endmacro() + +# This macro just adds generation of a map file with the same name as the executable and .map suffix +# to the linker command line. This works in older Cmake version (versions >= 3.13 have target_link_options) +# it should be a one to one replacement for add_executable +macro(add_mapped_executable target) + add_executable(${target} ${ARGN}) + target_link_libraries(${target} "-Wl,-Map=$<TARGET_PROPERTY:NAME>.map") + set_source_files_properties(${target}.map PROPERTIES GENERATED TRUE) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES ${target}.map) +endmacro() + +include(CTest) +include_directories(../src ../unittest inc ${PROJECT_BINARY_DIR}) + +add_subdirectory(unittest/src) + +# Codec 2 + +# Output path is such that #include <codec2/version.h> in codec2.h works +set(CODEC2_VERSION_PATH "${PROJECT_BINARY_DIR}/codec2") +configure_file ("${PROJECT_SOURCE_DIR}/../cmake/version.h.in" + "${CODEC2_VERSION_PATH}/version.h" ) + + +set(CODEC2_SRC ../src) +set(CODEC2_GEN_CODEBOOK_SRC ../build/src) +set(CODEC2_SRCS +${CODEC2_SRC}/lpc.c +${CODEC2_SRC}/nlp.c +${CODEC2_SRC}/postfilter.c +${CODEC2_SRC}/sine.c +${CODEC2_SRC}/codec2.c +${CODEC2_SRC}/codec2_fft.c +${CODEC2_SRC}/gp_interleaver.c +${CODEC2_SRC}/interldpc.c +${CODEC2_SRC}/kiss_fft.c +${CODEC2_SRC}/kiss_fftr.c +${CODEC2_SRC}/interp.c +${CODEC2_SRC}/lsp.c +${CODEC2_SRC}/ofdm.c +${CODEC2_SRC}/ofdm_mode.c +${CODEC2_SRC}/phase.c +${CODEC2_SRC}/quantise.c +${CODEC2_SRC}/pack.c +${CODEC2_SRC}/dump.c +${CODEC2_SRC}/cohpsk.c +${CODEC2_SRC}/fdmdv.c +${CODEC2_SRC}/freedv_api.c +${CODEC2_SRC}/freedv_1600.c +${CODEC2_SRC}/freedv_700.c +${CODEC2_SRC}/freedv_2020.c +${CODEC2_SRC}/freedv_fsk.c +${CODEC2_SRC}/filter.c +${CODEC2_SRC}/varicode.c +${CODEC2_SRC}/golay23.c +${CODEC2_SRC}/freedv_data_channel.c +${CODEC2_SRC}/newamp1.c +${CODEC2_SRC}/mbest.c +${CODEC2_SRC}/HRA_112_112.c +${CODEC2_SRC}/HRA_56_56.c +${CODEC2_SRC}/linreg.c +${CODEC2_SRC}/mpdecode_core.c +${CODEC2_SRC}/ldpc_codes.c +${CODEC2_SRC}/phi0.c +${CODEC2_SRC}/HRAb_396_504.c +${CODEC2_SRC}/codec2_math_arm.c +codebook.c +codebookd.c +codebookjmv.c +codebookge.c +codebooknewamp1_energy.c +codebooknewamp1.c +) + +set(STM32F4_ADAC_SRCS +src/stm32f4_adc.c +src/stm32f4_dac.c +../src/codec2_fifo.c +) +add_library(stm32f4_adac STATIC ${STM32F4_ADAC_SRCS}) +add_library(codec2 STATIC ${CODEC2_SRCS}) +add_library(codec2_prof STATIC ${CODEC2_SRCS}) +target_compile_definitions(codec2_prof PRIVATE PROFILE) + +set(SYSTEM_SRCS +src/system_stm32f4xx.c +src/startup_stm32f4xx.s +) + +add_library(sm1000base STATIC src/sm1000_leds_switches.c src/debugblinky.c ${SYSTEM_SRCS}) + +set(PROFILE_SYSTEM_SRCS +src/stm32f4_machdep.c +) + +list(APPEND PROFILE_SYSTEM_SRCS ${SYSTEM_SRCS}) + +#---------------------------- + +set(DAC_UT_SRCS +src/dac_ut.c +) +add_mapped_executable(dac_ut ${DAC_UT_SRCS}) +target_link_libraries(dac_ut stm32f4_adac stm32f4 sm1000base) +elf2bin(dac_ut) + +#---------------------------- + +set(USART_UT_SRCS +src/stm32f4_usart.c +src/usart_ut.c +) +add_mapped_executable(usart_ut ${USART_UT_SRCS}) +target_link_libraries(usart_ut stm32f4 sm1000base) +elf2bin(usart_ut) + +#---------------------------- + +set(USB_VCP +usb_conf/usb_bsp.c +usb_conf/usbd_desc.c +usb_conf/usbd_usr.c +usb_lib/cdc/usbd_cdc_core.c +usb_lib/cdc/usbd_cdc_vcp.c +usb_lib/core/usbd_core.c +usb_lib/core/usbd_ioreq.c +usb_lib/core/usbd_req.c +usb_lib/otg/usb_core.c +usb_lib/otg/usb_dcd.c +usb_lib/otg/usb_dcd_int.c) + +set(USB_VCP_UT +src/usb_vcp_ut.c +src/stm32f4_usb_vcp.c +) + +list(APPEND USB_VCP_UT ${USB_VCP}) + +add_definitions(-DUSE_USB_OTG_FS -DUSE_ULPI_PHY) +include_directories(usb_conf usb_lib/cdc usb_lib/core usb_lib/otg) + +add_mapped_executable(usb_vcp_ut ${USB_VCP_UT}) +target_link_libraries(usb_vcp_ut stm32f4 sm1000base) +elf2bin(usb_vcp_ut) + +set(ADC_REC_USB_SRCS +src/adc_rec_usb.c +src/stm32f4_usb_vcp.c +) + +add_mapped_executable(adc_rec_usb ${ADC_REC_USB_SRCS} ${USB_VCP}) +target_link_libraries(adc_rec_usb stm32f4_adac stm32f4 sm1000base) +elf2bin(adc_rec_usb) + +#---------------------------- + +set(SM1000_LEDS_SWITCHES_UT_SRCS +src/sm1000_leds_switches_ut.c +src/sm1000_leds_switches.c +) +add_mapped_executable(sm1000_leds_switches_ut ${SM1000_LEDS_SWITCHES_UT_SRCS}) +target_link_libraries(sm1000_leds_switches_ut stm32f4 sm1000base) +elf2bin(sm1000_leds_switches_ut) + +#---------------------------- + +set(SM1000_SRCS +src/sm1000_main.c +src/tone.c +src/sfx.c +src/sounds.c +src/morse.c +src/menu.c +src/tot.c +src/sm1000_leds_switches.c +../src/codec2_fifo.c +src/debugblinky.c +src/stm32f4_vrom.c +src/stm32f4_usart.c +src/memtools.c +) + +list(APPEND SM1000_SRCS ${CODEC2_SRCS}) + +add_mapped_executable(sm1000v5 ${SM1000_SRCS} ${SYSTEM_SRCS}) +target_link_libraries(sm1000v5 stm32f4_adac stm32f4 CMSIS) +target_compile_options(sm1000v5 PRIVATE "-O3") +elf2bin(sm1000v5) diff --git a/stm32/README.md b/stm32/README.md new file mode 100644 index 0000000..20be52c --- /dev/null +++ b/stm32/README.md @@ -0,0 +1,101 @@ +# Building for the stm32 + +## Quickstart + +1. Build codec2 (with -DUNITTEST=1) for your host system, see [codec2/README.md](../README.md) + ``` + $ cd ~/codec2 + $ mkdir build_linux && cd build_linux && cmake -DUNITTEST=1 .. && make + ``` + +2. Install a gcc arm toolchain: + ``` + $ cd ~ + $ wget https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2 + $ tar xvjf gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2 + $ export PATH=$HOME/gcc-arm-none-eabi-8-2018-q4-major/bin:$PATH + ``` + + NOTE: We do not recommend toolchains provided by popular + distributions (e.g. the Ubuntu 18 gcc-arm-none-eabi package will not + work). + +3. Create a build directory (```/path/to/codec2/stm32``` recommended to support unit tests) + ``` + $ cd /path/to/codec2/stm32 + $ mkdir build_stm32 + $ cd build_stm32 + ``` + +4. The STM32 Standard Peripheral Library is required. The download + requires a registration on the STM website. Save the zip file + somewhere safe and then extract it anywhere you like. You will have + to tell cmake where the unzipped library is by giving the variable + PERIPHLIBDIR the location of top level directory, e.g. for version + 1.8.0 this is STM32F4xx_DSP_StdPeriph_Lib_V1.8.0. + + In this example we will assume the library has been unzipped in ~/Downloads. + +5. Configure the build system by running cmake: + + ``` + $ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/STM32_Toolchain.cmake \ + -DPERIPHLIBDIR=~/Downloads/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 .. + ``` + Or a more general case: + ``` + $ cmake /path/to/codec2-dev/stm32 -DCMAKE_TOOLCHAIN_FILE=/path/to/codec2-dev/stm32/cmake/STM32_Toolchain.cmake \ + -DPERIPHLIBDIR=/path/to/unzipped/STM32F4xx_DSP_StdPeriph_Lib_Vx.x.x .. + ``` + +6. Build binaries (including sm1000.bin) + + Finally: + ``` + $ make + ``` + To see all the details during compilation: + ``` + $ make VERBOSE=1 + ``` + +## Flashing your SM1000 + +1. Power up your SM1000 with the PTT button down. Then flash it with: + +2. ``` + sudo dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D sm1000.bin + ``` +3. Power cycle to reboot. + +## Loading and Debugging stm32 programs + +1. See unitest/README.md for information on how to set up openocd. + +2. In one console Start openocd: + ``` + $ openocd -f board/stm32f4discovery.cfg + + ``` + +3. In another start gdb: + ``` + $ cd ~/codec2/stm32/build_stm32 + $ arm-none-eabi-gdb usart_ut.elf + (gdb) target remote :3333 + <snip> + (gdb) load + <snip> + (gdb) c + + ``` + +## Directories + +Directory | Notes +---|--- +cmake | cmake support files for the stm32 +doc | SM1000 documentation +inc | top level sm1000 source, drivers, and some legacy test code +src | top level sm1000 source, drivers, and some legacy test code +unittest | comprehensive set of automated unit tests for the stm32 700D port diff --git a/stm32/cmake/STM32_Lib.cmake b/stm32/cmake/STM32_Lib.cmake new file mode 100644 index 0000000..f336862 --- /dev/null +++ b/stm32/cmake/STM32_Lib.cmake @@ -0,0 +1,348 @@ +################################################### + +# Definitions for the STM32F4 Standard Peripheral Library + +#set(PERIPHLIBURL http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware) +#set(PERIPHLIBZIP stm32f4_dsp_stdperiph_lib.zip) +set(PERIPHLIBVER 1.8.0) +set(PERIPHLIBNAME STM32F4xx_DSP_StdPeriph_Lib_V) + +if(NOT PERIPHLIBDIR) + set(PERIPHLIBDIR ${CMAKE_SOURCE_DIR}/${PERIPHLIBNAME}${PERIPHLIBVER}) + message(STATUS "Using default path for StdPeriph Lib: ${PERIPHLIBDIR}") +endif() + +set(CMSIS ${PERIPHLIBDIR}/Libraries/CMSIS) +set(STM32F4LIB ${PERIPHLIBDIR}/Libraries/STM32F4xx_StdPeriph_Driver) +set(STM32F4TEMPLATE ${PERIPHLIBDIR}/Project/STM32F4xx_StdPeriph_Templates) +set(DSPLIB ${PERIPHLIBDIR}/Libraries/CMSIS/DSP_Lib) + +add_definitions(-DUSE_STDPERIPH_DRIVER -DARM_MATH_CM4 -DHSE_VALUE=\(\(uint32_t\)8000000\)) +include_directories(${STM32F4LIB}/inc ${STM32F4TEMPLATE} + ${CMSIS}/Include ${CMSIS}/Device/ST/STM32F4xx/Include) + + +set(STM32F4LIB_SRCS +${STM32F4LIB}/src/misc.c +${STM32F4LIB}/src/stm32f4xx_adc.c +${STM32F4LIB}/src/stm32f4xx_can.c +${STM32F4LIB}/src/stm32f4xx_cec.c +${STM32F4LIB}/src/stm32f4xx_crc.c +${STM32F4LIB}/src/stm32f4xx_cryp_aes.c +${STM32F4LIB}/src/stm32f4xx_cryp.c +${STM32F4LIB}/src/stm32f4xx_cryp_des.c +${STM32F4LIB}/src/stm32f4xx_cryp_tdes.c +${STM32F4LIB}/src/stm32f4xx_dac.c +${STM32F4LIB}/src/stm32f4xx_dbgmcu.c +${STM32F4LIB}/src/stm32f4xx_dcmi.c +${STM32F4LIB}/src/stm32f4xx_dma2d.c +${STM32F4LIB}/src/stm32f4xx_dma.c +${STM32F4LIB}/src/stm32f4xx_exti.c +${STM32F4LIB}/src/stm32f4xx_flash.c +${STM32F4LIB}/src/stm32f4xx_flash_ramfunc.c +${STM32F4LIB}/src/stm32f4xx_fmpi2c.c +${STM32F4LIB}/src/stm32f4xx_fsmc.c +${STM32F4LIB}/src/stm32f4xx_gpio.c +${STM32F4LIB}/src/stm32f4xx_hash.c +${STM32F4LIB}/src/stm32f4xx_hash_md5.c +${STM32F4LIB}/src/stm32f4xx_hash_sha1.c +${STM32F4LIB}/src/stm32f4xx_i2c.c +${STM32F4LIB}/src/stm32f4xx_iwdg.c +${STM32F4LIB}/src/stm32f4xx_ltdc.c +${STM32F4LIB}/src/stm32f4xx_pwr.c +${STM32F4LIB}/src/stm32f4xx_qspi.c +${STM32F4LIB}/src/stm32f4xx_rcc.c +${STM32F4LIB}/src/stm32f4xx_rng.c +${STM32F4LIB}/src/stm32f4xx_rtc.c +${STM32F4LIB}/src/stm32f4xx_sai.c +${STM32F4LIB}/src/stm32f4xx_sdio.c +${STM32F4LIB}/src/stm32f4xx_spdifrx.c +${STM32F4LIB}/src/stm32f4xx_spi.c +${STM32F4LIB}/src/stm32f4xx_syscfg.c +${STM32F4LIB}/src/stm32f4xx_tim.c +${STM32F4LIB}/src/stm32f4xx_usart.c +${STM32F4LIB}/src/stm32f4xx_wwdg.c +# Not compiling for now +# $(STM32F4LIB)/src/stm32f4xx_fmc.c +) + +add_library(stm32f4 STATIC ${STM32F4LIB_SRCS}) + + +set(CMSIS_SRCS +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_abs_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_abs_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_abs_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_abs_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_add_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_add_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_add_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_add_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_mult_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_mult_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_mult_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_mult_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_negate_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_negate_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_negate_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_negate_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_offset_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_offset_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_offset_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_offset_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_scale_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_scale_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_scale_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_scale_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_shift_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_shift_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_shift_q7.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_sub_f32.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_sub_q15.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_sub_q31.c +${CMSIS}/DSP_Lib/Source/BasicMathFunctions/arm_sub_q7.c +${CMSIS}/DSP_Lib/Source/CommonTables/arm_common_tables.c +${CMSIS}/DSP_Lib/Source/CommonTables/arm_const_structs.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c +${CMSIS}/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_init_f32.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q15.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q31.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_f32.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q15.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q31.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_f32.c +${CMSIS}/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_q31.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_cos_f32.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_cos_q15.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_cos_q31.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_sin_f32.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_sin_q15.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_sin_q31.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q15.c +${CMSIS}/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_conv_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_correlate_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q7.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_f32.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q31.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_q15.c +${CMSIS}/DSP_Lib/Source/FilteringFunctions/arm_lms_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_add_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_init_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f64.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q31.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_f32.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q15.c +${CMSIS}/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_max_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_max_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_max_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_max_q7.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_mean_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_mean_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_mean_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_mean_q7.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_min_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_min_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_min_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_min_q7.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_power_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_power_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_power_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_power_q7.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_rms_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_rms_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_rms_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_std_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_std_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_std_q31.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_var_f32.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_var_q15.c +${CMSIS}/DSP_Lib/Source/StatisticsFunctions/arm_var_q31.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_copy_f32.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_copy_q15.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_copy_q31.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_copy_q7.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_fill_f32.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_fill_q15.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_fill_q31.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_fill_q7.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_float_to_q15.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_float_to_q31.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_float_to_q7.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q15_to_float.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q15_to_q31.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q15_to_q7.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q31_to_float.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q31_to_q15.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q31_to_q7.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q7_to_float.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q7_to_q15.c +${CMSIS}/DSP_Lib/Source/SupportFunctions/arm_q7_to_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_bitreversal.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_bitreversal2.S +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_cfft_radix8_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_init_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_dct4_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_init_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_init_f32.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q31.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_q15.c +${CMSIS}/DSP_Lib/Source/TransformFunctions/arm_rfft_q31.c +) + +add_library(CMSIS STATIC ${CMSIS_SRCS}) +target_compile_options(CMSIS PRIVATE "-Wno-double-promotion") diff --git a/stm32/cmake/STM32_Toolchain.cmake b/stm32/cmake/STM32_Toolchain.cmake new file mode 100644 index 0000000..18d4667 --- /dev/null +++ b/stm32/cmake/STM32_Toolchain.cmake @@ -0,0 +1,15 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") + +# specify the cross compiler +set(CMAKE_C_COMPILER ${ARM_GCC_BIN}arm-none-eabi-gcc) +set(CMAKE_CXX_COMPILER ${ARM_GCC_BIN}arm-none-eabi-cpp) +set(CMAKE_ASM ${ARM_GCC_BIN}arm-none-eabi-as) +set(CMAKE_OBJCOPY ${ARM_GCC_BIN}arm-none-eabi-objcopy) +set(CMAKE_C_FLAGS_INIT "-specs=nosys.specs" CACHE STRING "Required compiler init flags") +set(CMAKE_CXX_FLAGS_INIT "-specs=nosys.specs" CACHE STRING "Required compiler init flags") +## https://stackoverflow.com/questions/10599038/can-i-skip-cmake-compiler-tests-or-avoid-error-unrecognized-option-rdynamic +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") diff --git a/stm32/cmake/arm_header.cmake b/stm32/cmake/arm_header.cmake new file mode 100644 index 0000000..7b9130e --- /dev/null +++ b/stm32/cmake/arm_header.cmake @@ -0,0 +1,64 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.4) + +#custom command to use objcopy to create .bin files out of ELF files +function(make_mbed_firmware INPUT) + add_custom_command(TARGET ${INPUT} + COMMAND arm-none-eabi-objcopy -O binary ${INPUT} ${INPUT}_${MBED_TARGET}.bin + COMMENT "objcopying to make mbed compatible firmware") + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${INPUT}_${MBED_TARGET}.bin) +endfunction(make_mbed_firmware) + +#assume we're using an LPC1768 model if it's not specified by -DMBED_TARGET= + if( NOT MBED_TARGET MATCHES "LPC1768" AND NOT MBED_TARGET MATCHES "LPC2368" AND NOT MBED_TARGET MATCHES "LPC11U24") + message(STATUS "invalid or no mbed target specified. Options are LPC1768, LPC2368 or LPC11U24. Assuming LPC1768 for now. + Target may be specified using -DMBED_TARGET=") + set(MBED_TARGET "LPC1768") +endif( NOT MBED_TARGET MATCHES "LPC1768" AND NOT MBED_TARGET MATCHES "LPC2368" AND NOT MBED_TARGET MATCHES "LPC11U24") + +set(MBED_INCLUDE "${CMAKE_SOURCE_DIR}/mbed/${MBED_TARGET}/GCC_CS/") + +#setup target specific object files +if(MBED_TARGET MATCHES "LPC1768") + set(MBED_PREFIX "LPC17") + set(CORE "cm3") + set(CHIP ${MBED_INCLUDE}sys.o + ${MBED_INCLUDE}startup_LPC17xx.o) +elseif(MBED_TARGET MATCHES "LPC2368") + set(CHIP ${MBED_INCLUDE}vector_functions.o + ${MBED_INCLUDE}vector_realmonitor.o + ${MBED_INCLUDE}vector_table.o) + set(MBED_PREFIX "LPC23") + set(CORE "arm7") +elseif(MBED_TARGET MATCHES "LPC11U24") + set(CHIP ${MBED_INCLUDE}sys.o + ${MBED_INCLUDE}startup_LPC11xx.o) + set(CORE "cm0") + set(MBED_PREFIX "LPC11U") +endif(MBED_TARGET MATCHES "LPC1768") + +#setup precompiled mbed files which will be needed for all projects +set(CHIP ${CHIP} + ${MBED_INCLUDE}system_${MBED_PREFIX}xx.o + ${MBED_INCLUDE}cmsis_nvic.o + ${MBED_INCLUDE}core_${CORE}.o) + +#force min size build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) +endif(NOT CMAKE_BUILD_TYPE) + +#set correct linker script +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \"-T${CMAKE_SOURCE_DIR}/mbed/${MBED_TARGET}/GCC_CS/${MBED_TARGET}.ld\" -static") + +#find CodeSourcery Toolchain for appropriate include dirs +find_path(CSPATH arm-none-eabi-g++ PATHS ENV) +message(STATUS "${CSPATH} is where CodeSourcery is installed") + +#setup directories for appropriate C, C++, mbed libraries and includes +include_directories(${MBED_INCLUDE}) +include_directories(mbed) +include_directories(${CSPATH}/../arm-none-eabi/include) +include_directories(${CSPATH}/../arm-none-eabi/include/c++/4.6.1) +link_directories(${MBED_INCLUDE}) diff --git a/stm32/cmake/gencodebooks.cmake b/stm32/cmake/gencodebooks.cmake new file mode 100644 index 0000000..1ead372 --- /dev/null +++ b/stm32/cmake/gencodebooks.cmake @@ -0,0 +1,173 @@ +# +# Generated sources +# + +set(D ${CMAKE_CURRENT_SOURCE_DIR}/../src/codebook) + +# lsp quantisers + +set(CODEBOOKS + ${D}/lsp1.txt + ${D}/lsp2.txt + ${D}/lsp3.txt + ${D}/lsp4.txt + ${D}/lsp5.txt + ${D}/lsp6.txt + ${D}/lsp7.txt + ${D}/lsp8.txt + ${D}/lsp9.txt + ${D}/lsp10.txt +) + +# lspd quantisers + +set(CODEBOOKSD + ${D}/dlsp1.txt + ${D}/dlsp2.txt + ${D}/dlsp3.txt + ${D}/dlsp4.txt + ${D}/dlsp5.txt + ${D}/dlsp6.txt + ${D}/dlsp7.txt + ${D}/dlsp8.txt + ${D}/dlsp9.txt + ${D}/dlsp10.txt +) + +set(CODEBOOKSJMV + ${D}/lspjmv1.txt + ${D}/lspjmv2.txt + ${D}/lspjmv3.txt +) + +set(CODEBOOKSMEL + ${D}/mel1.txt + ${D}/mel2.txt + ${D}/mel3.txt + ${D}/mel4.txt + ${D}/mel5.txt + ${D}/mel6.txt +) + +set(CODEBOOKSLSPMELVQ + ${D}/lspmelvq1.txt + ${D}/lspmelvq2.txt + ${D}/lspmelvq3.txt +) + +set(CODEBOOKSGE ${D}/gecb.txt) + +set(CODEBOOKSNEWAMP1 + ${D}/train_120_1.txt + ${D}/train_120_2.txt +) + +set(CODEBOOKSNEWAMP1_ENERGY + ${D}/newamp1_energy_q.txt +) + +set(CODEBOOKSNEWAMP2 + ${D}/codes_450.txt +) + +set(CODEBOOKSNEWAMP2_ENERGY + ${D}/newamp2_energy_q.txt +) + +# when crosscompiling we need a native executable +if(CMAKE_CROSSCOMPILING) + include(ExternalProject) + set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/..) + ExternalProject_Add(codec2_native + SOURCE_DIR ${SOURCE_DIR} + BINARY_DIR ${CMAKE_BINARY_DIR}/src/codec2_native + CONFIGURE_COMMAND ${CMAKE_COMMAND} ${SOURCE_DIR} + BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/src/codec2_native --target generate_codebook + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy src/generate_codebook ${CMAKE_CURRENT_BINARY_DIR} + ) + add_executable(generate_codebook IMPORTED) + set_target_properties(generate_codebook + PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/generate_codebook) + add_dependencies(generate_codebook codec2_native) +else(CMAKE_CROSSCOMPILING) +# Build code generator binaries. These do not get installed. + # generate_codebook + add_executable(generate_codebook generate_codebook.c) + target_link_libraries(generate_codebook ${CMAKE_REQUIRED_LIBRARIES}) + # Make native builds available for cross-compiling. + export(TARGETS generate_codebook + FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake) +endif(CMAKE_CROSSCOMPILING) + + +# codebook.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebook.c + COMMAND generate_codebook lsp_cb ${CODEBOOKS} > ${CMAKE_CURRENT_BINARY_DIR}/codebook.c + DEPENDS generate_codebook ${CODEBOOKS} +) + +# codebookd.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookd.c + COMMAND generate_codebook lsp_cbd ${CODEBOOKSD} > ${CMAKE_CURRENT_BINARY_DIR}/codebookd.c + DEPENDS generate_codebook ${CODEBOOKSD} +) + +# codebookjmv.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookjmv.c + COMMAND generate_codebook lsp_cbjmv ${CODEBOOKSJMV} > ${CMAKE_CURRENT_BINARY_DIR}/codebookjmv.c + DEPENDS generate_codebook ${CODEBOOKSJMV} +) + + +# codebookmel.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookmel.c + COMMAND generate_codebook mel_cb ${CODEBOOKSMEL} > ${CMAKE_CURRENT_BINARY_DIR}/codebookmel.c + DEPENDS generate_codebook ${CODEBOOKSMEL} +) + +# codebooklspmelvq.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooklspmelvq.c + COMMAND generate_codebook lspmelvq_cb ${CODEBOOKSLSPMELVQ} > ${CMAKE_CURRENT_BINARY_DIR}/codebooklspmelvq.c + DEPENDS generate_codebook ${CODEBOOKSLSPMELVQ} +) + +# codebookge.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebookge.c + COMMAND generate_codebook ge_cb ${CODEBOOKSGE} > ${CMAKE_CURRENT_BINARY_DIR}/codebookge.c + DEPENDS generate_codebook ${CODEBOOKSGE} +) + +# codebooknewamp1.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp1.c + COMMAND generate_codebook newamp1vq_cb ${CODEBOOKSNEWAMP1} > ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp1.c + DEPENDS generate_codebook ${CODEBOOKSNEWAMP1} +) + +# codebooknewamp1_energy.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp1_energy.c + COMMAND generate_codebook newamp1_energy_cb ${CODEBOOKSNEWAMP1_ENERGY} > ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp1_energy.c + DEPENDS generate_codebook ${CODEBOOKSNEWAMP1_ENERGY} +) + +# codebooknewamp2.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp2.c + COMMAND generate_codebook newamp2vq_cb ${CODEBOOKSNEWAMP2} > ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp2.c + DEPENDS generate_codebook ${CODEBOOKSNEWAMP2} +) + +# codebooknewamp2_energy.c +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp2_energy.c + COMMAND generate_codebook newamp2_energy_cb ${CODEBOOKSNEWAMP2_ENERGY} > ${CMAKE_CURRENT_BINARY_DIR}/codebooknewamp2_energy.c + DEPENDS generate_codebook ${CODEBOOKSNEWAMP2_ENERGY} +) + diff --git a/stm32/doc/3dot5mm_cable_config.png b/stm32/doc/3dot5mm_cable_config.png Binary files differnew file mode 100644 index 0000000..4e585d1 --- /dev/null +++ b/stm32/doc/3dot5mm_cable_config.png diff --git a/stm32/doc/sm1000_cn12.png b/stm32/doc/sm1000_cn12.png Binary files differnew file mode 100644 index 0000000..32da142 --- /dev/null +++ b/stm32/doc/sm1000_cn12.png diff --git a/stm32/doc/sm1000_cn12_rev2.odg b/stm32/doc/sm1000_cn12_rev2.odg Binary files differnew file mode 100644 index 0000000..a4891fa --- /dev/null +++ b/stm32/doc/sm1000_cn12_rev2.odg diff --git a/stm32/doc/sm1000_cn12_rev2.png b/stm32/doc/sm1000_cn12_rev2.png Binary files differnew file mode 100644 index 0000000..e82ef7d --- /dev/null +++ b/stm32/doc/sm1000_cn12_rev2.png diff --git a/stm32/doc/sm1000_cn4_cn12.jpg b/stm32/doc/sm1000_cn4_cn12.jpg Binary files differnew file mode 100644 index 0000000..de50d6c --- /dev/null +++ b/stm32/doc/sm1000_cn4_cn12.jpg diff --git a/stm32/doc/sm1000_enc_sm.jpg b/stm32/doc/sm1000_enc_sm.jpg Binary files differnew file mode 100644 index 0000000..e64d48d --- /dev/null +++ b/stm32/doc/sm1000_enc_sm.jpg diff --git a/stm32/doc/sm1000_manual.md b/stm32/doc/sm1000_manual.md new file mode 100644 index 0000000..521f0a1 --- /dev/null +++ b/stm32/doc/sm1000_manual.md @@ -0,0 +1,184 @@ +# SM1000 Manual + + + +# Getting Started + +1. Connect 12V, set the volume to half way and power on. You will hear morse playing the firmware version number (e.g. "V4") and the current mode. + +1. The SELECT button steps through the mode: + + Analog pass through (ANA) + + FreeDV 1600 (1600) + + FreeDV 700D (700D) + + FreeDV 700E (700E) + +1. Select 1600 mode. + +1. Connect the SM1000 ***Rig SPKR 3.5mm connector*** to your PC or laptop 3.5mm headphone socket. + +1. Download and play the [ve9qrp_1600.wav](https://github.com/drowe67/freedv-gui/tree/master/wav) sample from your PC or laptop to the SM1000. + +1. Adjust ***RIG SPKR Trimmer*** on the top of the SM1000 with a screwdriver until the clip/error LED on the front stops blinking. Occasional blinks are OK. If it blinks all the time you are clipping. + +1. If all is well you will hear decoded speech from the SM1000 speaker. + +1. Change modes to 700D with SELECT and try the [ve9qrp_700d.wav](https://github.com/drowe67/freedv-gui/tree/master/wav) sample. + +# Connection to your Radio + +This is the hardest part of SM1000 set up and will take some time. + +***Sorry, we do not have specific instructions for your radio***. + +Study the wiring of you radio, the [SM1000 schematic](https://svn.code.sf.net/p/freetel/code/smartmic/SM1000-F/MFG-SM1000-F/SCH-SM1000-F.pdf) **Rig Interface** section, and this section of the manual. Draw a schematic or wiring diagram. Take it slowly. Connect one part of the interface at at time and test. For example start with PTT. When that is working, connect receive audio and test, then transmit audio. + +1. You can connect the SM1000 to your radio using the 3.5mm sockets or the RJ45 connector. The RIG MIC, RIG SPKR and RIG PTT signals are connected in parallel to the 3.5mm sockets and the RJ45. + +  + +1. Stereo 3.5mm plugs should be used if possible. The stereo 3.5mm SM1000 sockets are wired to use the sleeve for ground and tip for signal, with ring unconnected. + +1. RJ45 connection to your radio – The CN12 Patch Panel is configured to connect the audio and PTT connections to your radio. You only need to configure the CN12 Patch Panel if you are using the RJ45. If you are using the 3.5mm connectors you do not need to configure the CN12 Patch Panel. Here is an example for a Yaesu radio: + +  +  + +1. All grounds are floating (unconnected) by default, but can be connected together using the extra ground connections on CN12. In the Yaesu example above all grounds are connected together using the wires between pins 10-13 and 11-12. Some radios have a separate microphone ground. + +1. Some radios have reversed numbering for their RJ45. + +1. Use 5cm lengths of 24GA (0.5mm) maximum diameter solid core wire for the patch panel. Using wire greater than 24GA (0.5mm) may damage the patch panel sockets. Insert one end of the wire at a time using needle nose pliers. + +1. For level set up, you can adjust the RIG SPKR, MIC GAIN, and RIG MIC trimmers through holes in the SM1000 top cover. + +1. On receive, adjust the radio volume (AF gain) and/or SM1000 RIG SPKR trimmer R52 so the clip/error led is not blinking. The receive level is not critical. It doesn’t work better with a louder signal. FreeDV 1600 and 700D use phase shift keying so are level insensitive. Constant clipping on the audio is bad, when this happens you’ll see the error led blink. + +1. Press PTT, and adjust MIC GAIN trimmer R42 so that the clip led just blinks occasionally, at the peaks of yr speech. Once again, this is not very critical, as it’s Digital Voice. A louder microphone signal won’t make your signal stronger. However a badly clipped mic signal will sound bad. Note on some versions MIC GAIN increases when turned anticlockwise. + +1. Jumper J5 selects high or low range RIG MIC level. Add J5 if your radio requires a “line level” mic input of several hundred mVpp. Remove J5 for low, mV level mic input into your radio. Then finely adjust the RIG MIC level with R47 (next step). Prior to Rev E it is possible to solder a resistor onto your SM1000 to achieve the same boost in mic input level. + +1. The RIG MIC trimmer R47 is the most critical. This controls the level of the modem signal sent to your radio on transmit. With PTT pressed and your radio transmitting adjust RIG MIC so that your radio ALC is just moving. Too much transmit drive will lead to a distorted modem signal, splatter on adjacent frequencies, and bit errors. Your Digital Voice signal will not be improved! Over driving transmitters when using digital voice is the most common mistake for new users! For finer adjustment use a 2nd receiver to monitoring your FreeDV transmission. Connect this receiver to the x86 PC version of FreeDV to monitor the spectrum and scatter plot. Here is a blog post and video [describing](http://www.rowetel.com/?p=3109) scatter plots and how they can be used to tune your FreeDV transmission. + +1. External Microphone – Jumper J3 provides electret microphone DC bias. Remove J3 if you do not want DC bias. + +1. External Speaker – The SM1000 3.5mm sockets are wired to use stereo or mono plugs. If you wish to use a mono plug for Ext Spkr (CN8) remove the jumper J2 on the PCB. This prevents a mono plug shorting the speaker amplifier output to ground resulting in no audio. Note the first production SM1000 (Rev D) did not have jumper J2 and should only be used with a stereo plug. + +# Morse Menus + +The SM1000 has a comprehensive menu system with morse code prompts developed by Stuart, VK4MSL. + +There are two buttons for UI operation, SELECT and BACK. Outside of the menu, these simply cycle between the available modes. The current mode is announced (morse code) after a short delay. + +Holding down SELECT puts you in menu mode. The POWER LED will now flash to indicate this. To navigate, press the SELECT and BACK buttons momentarily to move up and down in the menu. Again, after a pause the item will be read out. Holding SELECT or BACK either chooses the option, or backs out. + +Pressing PTT while in a menu exits the entire menu tree without saving changes to flash storage. + +The menu structure looks like this: +``` + -> Root menu: + |---> "MODE": Boot-up Operating mode + | |---> "ANA": Analogue mode + | |---> "1600": FreeDV 1600 + | |---> "700D": FreeDV 700D + | '---> "700E": FreeDV 700E + | + |---> "TOT": Time-out timer + | |---> "TIME": Total time-out period (0 == disabled) + | | 0-10 minutes in 5 second steps + | '---> "WARN": Warning beep period (0 == disabled) + | 0-${TIME} seconds in 5 second steps + | + '---> "UI": User interface options + |---> "FREQ": Morse frequency + | 50-2000 Hz in 50Hz steps + |---> "WPM": Morse send speed (PARIS standard) + | 5-60 WPM in 5 WPM steps + '---> "VOL": Menu volume + 1-15 units. +``` +Settings are saved when you hold down BACK to leave the root menu. + +# Flashing Your SM1000 + +You can program the flash memory on your SM1000 via USB using a Windows or Linux PC. Download the latest SM1000 firmware here: + +| Version | Date | Download .bin | Release Notes | +|:---:|---|---|---| +| 1 | May 2015 | [sm1000.bin](http://www.rowetel.com/downloads/codec2/smartmic/sm1000.bin) | Original release with FreeDV 1600 | +| 2 | July 2019 | [sm1000v2.bin](http://www.rowetel.com/downloads/codec2/smartmic/sm1000v2.bin) | FreeDV 700D and morse menus | +| 3 | March 2020 | [sm1000v3.bin](http://www.rowetel.com/downloads/codec2/smartmic/sm1000v3.bin) | Menu bug fixes, 700D modem improvements & automatic Mic EQ | +| 4 | May 2020 | [sm1000v4.bin](http://www.rowetel.com/downloads/codec2/smartmic/sm1000v4.bin) | 700D sync logic to reduce stop burbling with no signal | +| 5 | August 2021 | [sm1000v5.bin](http://www.rowetel.com/downloads/codec2/smartmic/sm1000v5.bin) | FreeDV 700E and Tx band pass filter for 700D & E | + +## Windows + +Find and install the **STM32CubeProgrammer** software by searching on the [ST web site](http://www.st.com). + +1. Connect the SM1000 USB to a Windows PC. +1. Apply power with PTT held down, then release PTT. +1. Run the `STM32CubeProgrammer` application and select the down arrow on the left side, and navigate to the "Erasing & Programming" section. +1. Select the `Verify programming` option. +1. In the "File path" on the left-hand side, select Open file and navigate to the .bin file you'd like to flash. +1. Select "USB" from the drop-down list on the upper right and push the Refresh button next to the Port drop-down in the "USB configuration" area. The SM1000 will appear as "USB1" or similar in the list; select that entry. +1. Click on the Connect button. +1. Ensure that "PID" displays as DF11 and "VID" as 0483. +1. Select `Start Programming` and the firmware procedure will commence. +1. A message in the log at the bottom of the window will display once complete. + +Power cycle the SM1000 and the new firmware will run. + +## Linux + +1. Apply power with PTT held down, then release PTT. +1. Connect the SM1000 to a Ubuntu Linux PC and type “dmesg”. You should see a STM32F4 boot device. +1. To flash the SM1000 + ``` + $ sudo apt-get install dfu-util + $ sudo dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D sm1000v5.bin + ``` + After about 10 seconds you will be returned to the command line. +1. Power cycle the SM1000 and the new firmware will run. + +# Tips + +1. A sound blaster record input connected to RIG MIC CN7 is a good way to test if the SM1000 is transmitting a signal. You can receive your FreeDV signal on the bench using FreeDV GUI on your PC. No radio is required for this test. + +1. Small external speakers and an external mic tend to make FreeDV sound better. A low cost analog headset works well. + +1. You may notice background noise from the SM1000 with no signal connected, especially at high volume levels. This becomes inaudible when the SM1000 is connected to a SSB radio in either analog or digital mode. + +1. The squelch threshold is fixed at 2dB for FreeDV 1600 and is off for 700D to optimise low SNR reception. However 700D will squelch if the Forward Error Correction (FEC) fails to decode. + +# Building the Firmware and Development + +1. [The SM1000 source code](https://github.com/drowe67/codec2/blob/master/stm32/README.md) + +1. You can use a STM32F4 Discovery board as an emulator pod for tetsing SM1000 firmware. + +1. [Comprehensive unit test system](https://github.com/drowe67/codec2/blob/master/stm32/unittest/README_unittest.md), thanks Don W7DMR. + +1. The SM1000 has a 115200 bit/s serial output from the 3 pin CN11 connector that dumps debug information as it runs. + +## Factory Reset + +To perform a factory reset, hold down BACK whilst powering the device on. A loud beep should be heard and the SYNC LED should flash. Release, and the device should boot up with factory defaults. + +# References + +1. [Support - Codec 2 Mailing List](https://lists.sourceforge.net/lists/listinfo/freetel-codec2). +1. [Buy a SM1000](http://rowetel.com/sm1000.html) - Your purchase supports FreeDV development +1. [SM1000 Ref F Schematic](https://svn.code.sf.net/p/freetel/code/smartmic/SM1000-F/MFG-SM1000-F/SCH-SM1000-F.pdf) +1. [SM1000 Hardware Design](https://svn.code.sf.net/p/freetel/code/smartmic) +1. [Series of blog posts on the SM1000 development](http://www.rowetel.com/?page_id=6172) (2014 section of archive) +1. Nice write up of a mobile [Codan NGT SM1000 installation](http://rfhead.net/?p=582) by Mark VK5QI including tips on testing and debugging a microphone level problem. +1. [Sample wiring](http://rowetel.com/downloads/freedv/vk5kx_radio_sm1000_connections_model.pdf) diagrams for several radios from Peter, VK5KX. These are not tested and provided as examples only. + +# Credits + +The SM1000 hardware was developed by David Rowe VK5DGR and Rick Barnich KA8BMA. It is being manufactured, tested and shipped by our good friend Edwin at Dragino in Shenzhen, China. + +Steve (K5OKC) helped develop the fine OFDM modem used for FreeDV 700D. Don (W7DMR), spearheaded the port of FreeDV 700D to the SM1000, including code optimisation and a comprehensive unit test system. Don, Danilo (DB4PLE), and Richard (KF5OIM) have done some fantastic work on the cmake build and test system for the stm32 port of 700D. Stuart VK4MSL developed the morse menu system for the SM1000. Mooneer, K6AQ, ported FreeDV 700E to the SM1000. + +Thanks also to the many Hams who kindly helped out with testing new firmware releases. + +This is an open source/open hardware project, developed by Hams - for Hams. Thanks! diff --git a/stm32/inc/debugblinky.h b/stm32/inc/debugblinky.h new file mode 100644 index 0000000..f2bb2da --- /dev/null +++ b/stm32/inc/debugblinky.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: debugblinky.h + AUTHOR......: David Rowe + DATE CREATED: 12 August 2014 + + Configures Port E GPIO pins used for debug blinkies, and control lines + for SM2000 +12V switching. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __DEBUGBLINKY__ +#define __DEBUGBLINKY__ + +void init_debug_blinky(void); +void txrx_12V(int state); + +#endif diff --git a/stm32/inc/memtools.h b/stm32/inc/memtools.h new file mode 100644 index 0000000..b4fa8be --- /dev/null +++ b/stm32/inc/memtools.h @@ -0,0 +1,13 @@ +/* + memtools.h + June 2019 + + Tools for anlysing and debugging memory on stm32. See also debug_alloc.h +*/ + +#ifndef __MEMTOOLS__ +#define __MEMTOOLS__ +void memtools_find_unused( int (*printf_func)(const char *fmt, ...) ); +register char * memtools_sp asm ("sp"); +void memtools_isnan(float *vec, int n, char *label, int (*printf_func)(const char *fmt, ...)); +#endif diff --git a/stm32/inc/menu.h b/stm32/inc/menu.h new file mode 100644 index 0000000..f93601b --- /dev/null +++ b/stm32/inc/menu.h @@ -0,0 +1,92 @@ +#ifndef _MENU_H +#define _MENU_H +/*! + * Callback driven menu handler. + * + * The following is an implementation of a callback-driven menu system. + * It supports arbitrary levels of menus (limited by size of return stack) + * and supports arbitrary user events. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> + +#define MENU_STACK_SZ 8 /*!< Size of the menu return stack */ + +#define MENU_EVT_ENTERED 0 /*!< Menu item has been entered */ +#define MENU_EVT_RETURNED 1 /*!< We have returned from a submenu */ + +/*! Menu state structure */ +struct menu_t { + /*! The last seen menu item */ + const struct menu_item_t* last; + /*! Currently selected item index */ + uint32_t current; + /*! Current menu item stack */ + struct menu_stack_item_t { + const struct menu_item_t* item; + uint32_t index; + } stack[MENU_STACK_SZ]; + /*! Present depth of the stack */ + uint8_t stack_depth; +}; + +/*! Menu item structure */ +struct menu_item_t { + /*! Morse-code label for the menu item */ + const char* label; + /*! Event callback pointer for menu item */ + void (*event_cb)( + struct menu_t* const menu, + uint32_t event); + /*! Children of this menu item */ + const struct menu_item_t** const children; + uint32_t num_children; + /*! Arbitrary data */ + union menu_item_data_t { + /*! Arbitrary pointer */ + const void* p; + /*! Arbitrary unsigned integer */ + uintptr_t ui; + /*! Arbitrary signed integer */ + intptr_t si; + } data; +}; + +/*! + * Return the Nth item on the stack. + */ +const struct menu_item_t* const menu_item( + const struct menu_t* const menu, uint8_t index); + +/*! + * Enter a (sub)-menu. + * @retval -1 Stack is full + * @retval 0 Success + */ +int menu_enter(struct menu_t* const menu, + const struct menu_item_t* const item); + +/*! Return from a (sub)-menu */ +void menu_leave(struct menu_t* const menu); + +/*! + * Execute the callback for the current item with a user-supplied event. + */ +void menu_exec(struct menu_t* const menu, uint32_t event); + +#endif diff --git a/stm32/inc/morse.h b/stm32/inc/morse.h new file mode 100644 index 0000000..632f2e2 --- /dev/null +++ b/stm32/inc/morse.h @@ -0,0 +1,65 @@ +#ifndef _MORSE_H +#define _MORSE_H +/*! + * Morse code library. + * + * This implements a state machine for playing back morse code messages. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "sfx.h" + +/*! + * Maximum length of a morse symbol, including gaps and termination. + * Allowing for 8 actual sub-symbols (dahs and dits), that's up to + * 8 gaps between plus a terminator. + */ +#define MORSE_SYM_LEN (17) + +/*! + * Morse code playback state machine + */ +struct morse_player_t { + /*! Symbol being transmitted */ + struct sfx_note_t sym[MORSE_SYM_LEN]; + /*! + * Pointer to the string being emitted. Playback is finished + * when this is NULL. + */ + const char* msg; + /*! Sound effect player state machine */ + struct sfx_player_t sfx_player; + /*! "Dit" period in milliseconds */ + uint16_t dit_time; + /*! Tone frequency */ + uint16_t freq; +}; + +/*! + * Play a morse code message. + * @param morse_player Morse code player state machine + * @param msg Message to play back (NULL == stop) + */ +void morse_play(struct morse_player_t* const morse_player, + const char* msg); + +/*! + * Retrieve the next sample to be played. + */ +int16_t morse_next(struct morse_player_t* const morse_player); + +#endif diff --git a/stm32/inc/sfx.h b/stm32/inc/sfx.h new file mode 100644 index 0000000..9745018 --- /dev/null +++ b/stm32/inc/sfx.h @@ -0,0 +1,63 @@ +#ifndef _SFX_H +#define _SFX_H +/*! + * Sound effect player library. + * + * This implements a state machine for playing back various monophonic + * sound effects such as morse code symbols, clicks and alert tones. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "tone.h" + +/*! + * A sound effect "note" + */ +struct sfx_note_t { + /*! Note frequency. 0 == pause */ + uint16_t freq; + /*! Note duration in msec. 0 == end of effect */ + uint16_t duration; +}; + +/*! + * Sound effect player state machine + */ +struct sfx_player_t { + /*! + * Pointer to the current "note". When this is NULL, + * playback is complete. + */ + const struct sfx_note_t* note; + /*! Tone generator state machine */ + struct tone_gen_t tone_gen; +}; + +/*! + * Start playing a particular effect. + * @param sfx_player Effect player state machine + * @param effect Pointer to sound effect (NULL == stop) + */ +void sfx_play(struct sfx_player_t* const sfx_player, + const struct sfx_note_t* effect); + +/*! + * Retrieve the next sample to be played. + */ +int16_t sfx_next(struct sfx_player_t* const sfx_player); + +#endif diff --git a/stm32/inc/sm1000_leds_switches.h b/stm32/inc/sm1000_leds_switches.h new file mode 100644 index 0000000..a5cbc2a --- /dev/null +++ b/stm32/inc/sm1000_leds_switches.h @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: sm1000_leds_switches.h + AUTHOR......: David Rowe + DATE CREATED: 18 July 2014 + + Functions for controlling LEDs and reading switches on SM1000. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LEDS_SWITCHES__ +#define __LEDS_SWITCHES__ + +#include <stdint.h> + +void sm1000_leds_switches_init(void); + +#define LED_ON 1 /*!< Turn LED on */ +#define LED_OFF 0 /*!< Turn LED off */ +#define LED_INV -1 /*!< Invert LED state */ + +void led_pwr(int state); +void led_ptt(int state); +void led_rt(int state); +void led_err(int state); +void not_cptt(int state); + +int switch_ptt(void); +int switch_select(void); +int switch_back(void); +int ext_ptt(void); + +#define DEBOUNCE_DELAY 50 /*!< Delay to wait while switch bounces */ + +#define SW_STEADY 0 /*!< Switch is in steady-state */ +#define SW_DEBOUNCE 1 /*!< Switch is being debounced */ + +/*! Switch debounce and logic handling */ +struct switch_t { + /*! Debounce/hold timer */ + uint32_t timer; + /*! Current/debounced observed switch state */ + uint8_t sw; + /*! Raw observed switch state (during debounce) */ + uint8_t raw; + /*! Last steady-state switch state */ + uint8_t last; + /*! Debouncer state */ + uint8_t state; +}; + +/*! Update the state of a switch */ +void switch_update(struct switch_t* const sw, uint8_t state); + +/*! Acknowledge the current state of the switch */ +void switch_ack(struct switch_t* const sw); + +/*! Return how long the switch has been pressed in ticks. */ +uint32_t switch_pressed(const struct switch_t* const sw); + +/*! Return non-zero if the switch has been released. */ +int switch_released(const struct switch_t* const sw); + +/*! Count the tick timers on the switches. */ +void switch_tick(struct switch_t* const sw); + +void ColorfulRingOfDeath(int code); + +#endif diff --git a/stm32/inc/sounds.h b/stm32/inc/sounds.h new file mode 100644 index 0000000..9ccfeb7 --- /dev/null +++ b/stm32/inc/sounds.h @@ -0,0 +1,38 @@ +#ifndef _SOUNDS_H +#define _SOUNDS_H +/*! + * Sound effect library. + * + * This provides some sound effects for the SM1000 UI. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "sfx.h" + +/*! Start-up tune / selected tune */ +extern const struct sfx_note_t sound_startup[]; + +/*! Returned tune */ +extern const struct sfx_note_t sound_returned[]; + +/*! Click sound */ +extern const struct sfx_note_t sound_click[]; + +/*! Death march tune */ +extern const struct sfx_note_t sound_death_march[]; + +#endif diff --git a/stm32/inc/stm32f4_adc.h b/stm32/inc/stm32f4_adc.h new file mode 100644 index 0000000..c7884a9 --- /dev/null +++ b/stm32/inc/stm32f4_adc.h @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_adc.h + AUTHOR......: David Rowe + DATE CREATED: 30 May 2014 + + Two channel FIFO buffered ADC driver module for STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __STM32F4_ADC__ +#define __STM32F4_ADC__ + +#define ADC_BUF_SZ 320 + +/* divisors for various sample rates */ + +#define ADC_FS_8KHZ 10500 +#define ADC_FS_16KHZ 5250 +#define ADC_FS_48KHZ 1750 +#define ADC_FS_96KHZ 875 + +void adc_open(int fs_divisor, int fifo_sz, short *buf1, short *buf2); +int adc1_read(short buf[], int n); /* ADC1 Pin PA1 */ +int adc2_read(short buf[], int n); /* ADC2 Pin PA2 */ +int adc1_samps(); +int adc2_samps(); + +#endif diff --git a/stm32/inc/stm32f4_dac.h b/stm32/inc/stm32f4_dac.h new file mode 100644 index 0000000..9bf0b9a --- /dev/null +++ b/stm32/inc/stm32f4_dac.h @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_dac.h + AUTHOR......: David Rowe + DATE CREATED: 1 June 2013 + + Two channel FIFO buffered DAC driver module for STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __STM32F4_DAC__ +#define __STM32F4_DAC__ + +#define DAC_BUF_SZ 320 + +/* divisors for various sample rates */ + +#define DAC_FS_8KHZ 10500 +#define DAC_FS_16KHZ 5250 +#define DAC_FS_48KHZ 1750 +#define DAC_FS_96KHZ 875 + +void dac_open(int fs_divisor, int fifo_sz, short *buf1, short *buf2); +int dac1_write(short buf[], int n, int limit); /* DAC1 pin PA4 */ +int dac1_free(); +int dac2_write(short buf[], int n, int limit); /* DAC2 pin PA5 */ +int dac2_free(); + +#endif diff --git a/stm32/inc/stm32f4_usart.h b/stm32/inc/stm32f4_usart.h new file mode 100644 index 0000000..8a37a6d --- /dev/null +++ b/stm32/inc/stm32f4_usart.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_usart.h + AUTHOR......: David Rowe + DATE CREATED: May 2019 + + Basic USART tty support for the stm32. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2019 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __STM32F4_USART__ +#define __STM32F4_USART__ + +void usart_init(); +void usart_puts(const char s[]); +int usart_printf(const char *fmt, ...); + +#endif diff --git a/stm32/inc/stm32f4_usb_vcp.h b/stm32/inc/stm32f4_usb_vcp.h new file mode 100644 index 0000000..d742ebc --- /dev/null +++ b/stm32/inc/stm32f4_usb_vcp.h @@ -0,0 +1,24 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_usb_vcp.h + AUTHOR......: David Rowe + DATE CREATED: 4 Sep 2014 + + USB Virtual COM Port (VCP) module. + +\*---------------------------------------------------------------------------*/ + +#ifndef __STM32F4_USB_VCP__ +#define __STM32F4_USB_VCP__ + +#include <stdint.h> + +void usb_vcp_init(void); + +int VCP_get_char(uint8_t *buf); +int VCP_get_string(uint8_t *buf); +void VCP_put_char(uint8_t buf); +void VCP_send_str(uint8_t* buf); +void VCP_send_buffer(uint8_t* buf, int len); + +#endif diff --git a/stm32/inc/stm32f4_vrom.h b/stm32/inc/stm32f4_vrom.h new file mode 100644 index 0000000..e878b9c --- /dev/null +++ b/stm32/inc/stm32f4_vrom.h @@ -0,0 +1,70 @@ +#ifndef _STM32F4_VROM_H_ +#define _STM32F4_VROM_H_ +/*! + * STM32F4 Virtual EEPROM driver + * + * This module implements a crude virtual EEPROM device stored in on-board + * flash. The STM32F405 has 4 16kB flash sectors starting at address + * 0x80000000, followed by a 64kB sector, then 128kB sectors. + * + * The Cortex M4 core maps these all to address 0x00000000 when booting + * from normal flash, so the first sector is reserved for interrupt + * vectors. + * + * Everything else however is free game, and so we use these smaller + * sectors to store our configuration. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <errno.h> + +/*! + * Read data from a virtual EEPROM. + * @param rom ROM ID to start reading. + * @param offset Address offset into ROM to start reading. + * @param size Number of bytes to read from ROM. + * @param out Buffer to write ROM content to. + * @returns Number of bytes read from ROM. + * @retval -ENXIO No valid data found for address. + * @retval -ESPIPE Offset past end of ROM. + */ +int vrom_read(uint8_t rom, uint16_t offset, uint16_t size, void* out); + +/*! + * Write data to a virtual EEPROM. + * @param rom ROM ID to start writing. + * @param offset Address offset into ROM to start writing. + * @param size Number of bytes to write to ROM. + * @param in Buffer to write ROM content from. + * @returns Number of bytes written to ROM. + * @retval -EIO Programming failed + * @retval -ENOSPC No free blocks available + */ +int vrom_write(uint8_t rom, uint16_t offset, uint16_t size, + const void* in); + +/*! + * Erase a virtual EEPROM. + * @param rom ROM ID to erase. + * @returns Number of bytes written to ROM. + * @retval -EIO Programming failed + * @retval -ENOSPC No free blocks available + */ +int vrom_erase(uint8_t rom); + +#endif diff --git a/stm32/inc/stm32f4xx_conf.h b/stm32/inc/stm32f4xx_conf.h new file mode 100644 index 0000000..69047b1 --- /dev/null +++ b/stm32/inc/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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* 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/stm32/inc/tone.h b/stm32/inc/tone.h new file mode 100644 index 0000000..b7441ca --- /dev/null +++ b/stm32/inc/tone.h @@ -0,0 +1,84 @@ +#ifndef _TONE_H +#define _TONE_H +/*! + * Fixed-point tone generator. + * + * The code here implements a simple fixed-point tone generator that uses + * integer arithmetic to generate a sinusoid at a fixed sample rate of + * 16kHz. + * + * To set the initial state of the state machine, you specify a frequency + * and duration using tone_reset. The corresponding C file embeds a + * sinusoid look-up table. The total number of samples is computed for + * the given time and used to initialise 'remain', 'time' is initialised + * to 0, and 'step' gives the amount to increment 'time' by each iteration. + * + * The samples are retrieved by repeatedly calling tone_next. This + * advances 'time' and decrements 'remain'. The tone is complete when + * 'remain' is zero. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> + +/*! Tone sampling rate in Hz. */ +#define TONE_FS 16000 + +/*! + * Tone generator state. This holds the current state of the tone + * generator in order to decide what sample to release next. + */ +struct tone_gen_t { + /*! Current sample. (Q12) */ + uint32_t sample; + /*! + * Time remaining in samples. (integer) Playback is finished + * when this reaches zero. + */ + uint16_t remain; + /*! + * Subsample step (Q12). This is the number of samples (or part + * thereof) to advance "sample". Special case: when zero, sample + * is not advanced, silence is generated instead. + */ + uint16_t step; +}; + +/*! + * Re-set the tone generator. + * + * @param tone_gen Tone generator to reset. + * @param freq Frequency in Hz, 0 = silence. + * @param duration Duration in milliseconds. 0 to stop. + */ +void tone_reset( + struct tone_gen_t* const tone_gen, + uint16_t freq, uint16_t duration); + +/*! + * Retrieve the next sample from the tone generator. + * @param tone_gen Tone generator to update. + */ +int16_t tone_next( + struct tone_gen_t* const tone_gen); + +/*! + * Retrieve the current time in milliseconds. + */ +uint32_t tone_msec(const struct tone_gen_t* const tone_gen); + +#endif diff --git a/stm32/inc/tot.h b/stm32/inc/tot.h new file mode 100644 index 0000000..ad635b0 --- /dev/null +++ b/stm32/inc/tot.h @@ -0,0 +1,115 @@ +#ifndef _TOT_H +#define _TOT_H +/*! + * Time-out timer. + * + * This is a simple time-out timer for ensuring a maximum transmission + * time is observed. The time-out timer is configured with a total time + * in "ticks", which get counted down in an interrupt. + * + * When the "warning" level is reached, a flag is repeatedly set permit + * triggering of LEDs/sounds to warn the user that time is nearly up. + * + * Upon timeout, a separate flag is set to indicate timeout has taken + * place. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> + +/*! + * Time-out timer state machine + */ +struct tot_t { + /*! + * Number of ticks remaining, if non-zero, transmission is + * in progress. + */ + uint32_t remaining; + /*! + * Number of ticks remaining, before next warning. + */ + uint32_t warn_remain; + /*! + * Timeout timer tick period. Used to reset the ticks counter. + */ + uint32_t tick_period; + /*! + * Number of ticks between the remaining warnings. + */ + uint16_t remain_warn_ticks; + /*! + * Event tick timer. Used to slow down the source timer. + */ + uint16_t ticks; + /*! + * Event flags. + */ + uint16_t event; +}; + +/*! + * Time-out timer has been started. + */ +#define TOT_EVT_START (1 << 0) + +/*! + * Start of warning period reached. + */ +#define TOT_EVT_WARN (1 << 1) + +/*! + * Next warning is due. + */ +#define TOT_EVT_WARN_NEXT (1 << 2) + +/*! + * Time-out reached. + */ +#define TOT_EVT_TIMEOUT (1 << 3) + +/*! + * Timer sequence complete + */ +#define TOT_EVT_DONE (1 << 4) + +/*! + * Reset the time-out timer. This zeroes the counter and event flags. + */ +void tot_reset(struct tot_t * const tot); + +/*! + * Start the time-out timer ticking. + */ +void tot_start(struct tot_t * const tot, uint32_t tot_ticks, + uint16_t warn_ticks); + +/*! + * Count a time-out timer tick. + */ +static inline void tot_tick(struct tot_t * const tot) +{ + if (tot->ticks) + tot->ticks--; +} + +/*! + * Update the time-out timer state. + */ +void tot_update(struct tot_t * const tot); + +#endif diff --git a/stm32/src/adc_rec_usb.c b/stm32/src/adc_rec_usb.c new file mode 100644 index 0000000..e5ab084 --- /dev/null +++ b/stm32/src/adc_rec_usb.c @@ -0,0 +1,85 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: adc_rec_usb.c + AUTHOR......: David Rowe + DATE CREATED: Nov 2015 + + Records a 16 kHz sample rate raw file from one of the ADC channels, + which are connected to pins PA1 (ADC1) and PA2 (ADC2). Uploads to the + host PC via the STM32F4 USB port, which appears as /dev/ttyACM0. + + On the SM1000: + ADC1 -> PA1 -> "from radio" + ADC2 -> PA2 -> "mic amp" + + I used this to record: + $ sudo dd if=/dev/ttyACM0 of=test.raw count=100 + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <math.h> +#include "stm32f4_adc.h" +#include "stm32f4_usb_vcp.h" +#include "sm1000_leds_switches.h" + +#define N (ADC_BUF_SZ*6) + +/* test tone parameters */ + +#define FREQ 999.0 /* make sure no alignment with frame boundaries */ +#define FS 16000.0 +#define AMP 10000.0 + +extern int adc_overflow1; +extern int adc_overflow2; + +int main(void){ + short buf[N]; + #ifdef TEST_TONE + float phase = 0.0; + float sam; + int i; + #endif + + usb_vcp_init(); + adc_open(ADC_FS_96KHZ, 4*N, NULL, NULL); + sm1000_leds_switches_init(); + + /* set up test buffer, lets us test USB comms indep of ADC, record to a file + then play back/examine waveform to make sure no clicks */ + + while(1) { + while(adc1_read(buf, N) == -1); + + #ifdef TEST_TONE + for(i=0; i<N; i++) { + phase += 2.0*M_PI*FREQ/FS; + phase -= 2.0*M_PI*floor(phase/(2.0*M_PI)); + sam = AMP*cos(phase); + buf[i] = (short)sam; + } + #endif + + led_pwr(1); + VCP_send_buffer((uint8_t*)buf, sizeof(buf)); + led_pwr(0); + } +} diff --git a/stm32/src/dac_ut.c b/stm32/src/dac_ut.c new file mode 100644 index 0000000..2edceb0 --- /dev/null +++ b/stm32/src/dac_ut.c @@ -0,0 +1,57 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: dac_ut.c + AUTHOR......: David Rowe + DATE CREATED: May 31 2013 + + Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board, + or the speaker output of the SM1000. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include "stm32f4_dac.h" + +#define SINE_SAMPLES 32 + +/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples + are 16 bit 2's complement, the DAC driver convertsto 12 bit + unsigned. */ + +short aSine[] = { + -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128, + 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384, + -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160, + -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416 +}; + +int main(void) { + + dac_open(DAC_FS_16KHZ, 4*DAC_BUF_SZ, 0, 0); + + while (1) { + + /* keep DAC FIFOs topped up */ + + dac1_write((short*)aSine, SINE_SAMPLES, 0); + dac2_write((short*)aSine, SINE_SAMPLES, 0); + } + +} diff --git a/stm32/src/debugblinky.c b/stm32/src/debugblinky.c new file mode 100644 index 0000000..992c8b0 --- /dev/null +++ b/stm32/src/debugblinky.c @@ -0,0 +1,57 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: debugblinky.c + AUTHOR......: David Rowe + DATE CREATED: 12 August 2014 + + Configures GPIO pins used for debug blinkies + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stm32f4xx.h" + +void init_debug_blinky(void) { + GPIO_InitTypeDef GPIO_InitStruct; + + /* PE0-3 used to indicate activity, PE4-5 for SM2000 +12V rail switching */ + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOE, &GPIO_InitStruct); +} + +/* SM2000: 0 for +12V RX power, 1 for +12V TX power */ + +void txrx_12V(int state) { + if (state) { + GPIOE->ODR &= ~(1 << 5); /* +12VRXENB off */ + GPIOE->ODR |= (1 << 4); /* +12VTXENB on */ + } + else { + GPIOE->ODR &= ~(1 << 4); /* +12VTXENB off */ + GPIOE->ODR |= (1 << 5); /* +12VRXENB on */ + } +} + diff --git a/stm32/src/memtools.c b/stm32/src/memtools.c new file mode 100644 index 0000000..431ceaf --- /dev/null +++ b/stm32/src/memtools.c @@ -0,0 +1,67 @@ +/* + memtools.h + June 2019 + + Tools for looking at memory on the stm32. See also debug_alloc.h +*/ + +#include <stdlib.h> +#include <sys/types.h> +#include <math.h> +#include "memtools.h" + +/* Required memory allocation wrapper for embedded platforms. For SM1000, we can just use stdlib's memory functions. */ +void* codec2_malloc(size_t size) +{ + return malloc(size); +} + +void* codec2_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + +void codec2_free(void* ptr) +{ + free(ptr); +} + +/* startup_stm32f4xx.s has been modified to fill RAM segment from bss up with 0x0x55555555 */ + +void memtools_find_unused( int (*printf_func)(const char *fmt, ...) ) { + int32_t *p, *start; + int found = 0; + + (*printf_func)("chunks of RAM segment > 256 bytes containing start up pattern:\n"); + + /* count down from top of memory through stack, empty memory, then to heap */ + for (p =(int32_t*)0x20000000; p<(int32_t*)0x20020000; p++) { + if (found == 0) { + if (*p == 0x55555555) { + start = p; + found = 1; + } + } + + if (found == 1) { + if (*p != 0x55555555) { + found = 0; + int bytes = (void*)p - (void*)start; + if (bytes >= 0x100) + (*printf_func)(" start: 0x%x end: 0x%x bytes: %d\n", (int) start, (int)p, bytes); + } + } + } + +} + +void memtools_isnan(float *vec, int n, char *label, int (*printf_func)(const char *fmt, ...)) { + int count = 0; + for(int i=0; i<n; i++) { + if (isnan(vec[i])) { + (*printf_func)("%s memtools_isnan: %d %p\n", label, i, &vec[i]); + if (count++ == 5) return; + } + } +} + diff --git a/stm32/src/menu.c b/stm32/src/menu.c new file mode 100644 index 0000000..cb8ba97 --- /dev/null +++ b/stm32/src/menu.c @@ -0,0 +1,98 @@ +/*! + * Callback driven menu handler. + * + * The following is an implementation of a callback-driven menu system. + * It supports arbitrary levels of menus (limited by size of return stack) + * and supports arbitrary user events. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "menu.h" +#include <stdlib.h> + +/*! + * Return the Nth item on the stack. + */ +static const struct menu_stack_item_t* const menu_stack( + const struct menu_t* const menu, + uint8_t index) +{ + if (menu->stack_depth <= index) + return NULL; + + return &(menu->stack[menu->stack_depth - index - 1]); +} + +/*! + * Return the Nth item on the stack. + */ +const struct menu_item_t* const menu_item( + const struct menu_t* const menu, uint8_t index) +{ + const struct menu_stack_item_t* const current + = menu_stack(menu, index); + + if (!current) + return NULL; + return current->item; +} + +/*! + * Enter a (sub)-menu. + */ +int menu_enter(struct menu_t* const menu, + const struct menu_item_t* const item) +{ + if (menu->stack_depth == MENU_STACK_SZ) + return -1; + + menu->stack[menu->stack_depth].item = item; + menu->stack[menu->stack_depth].index = menu->current; + menu->stack_depth++; + + (item->event_cb)(menu, MENU_EVT_ENTERED); + + return 0; +} + +/*! + * Return from a (sub)-menu. + */ +void menu_leave(struct menu_t* const menu) +{ + if (!menu->stack_depth) + return; /* Already out of the menu */ + + menu->last = menu_item(menu, 0); + menu->stack_depth--; + + const struct menu_stack_item_t* current = menu_stack(menu, 0); + if (current && current->item) { + menu->current = current->index; + (current->item->event_cb)(menu, MENU_EVT_RETURNED); + } +} + +/*! + * Execute the callback for the current item with a user-supplied event. + */ +void menu_exec(struct menu_t* const menu, uint32_t event) +{ + const struct menu_item_t* item = menu_item(menu, 0); + if (item && item->event_cb) + (item->event_cb)(menu, event); +} diff --git a/stm32/src/morse.c b/stm32/src/morse.c new file mode 100644 index 0000000..2522993 --- /dev/null +++ b/stm32/src/morse.c @@ -0,0 +1,175 @@ +/*! + * Morse code library. + * + * This implements a state machine for playing back morse code messages. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include "morse.h" + +#include <stdio.h> + +/*! Symbol table element definition */ +struct morse_sym_table_t { + uint8_t code; uint8_t len; +}; + +/*! Symbol table: "digits" */ +static const struct morse_sym_table_t morse_digits[] = { + { .code = 0xf8, .len = 5 }, /* 0: ----- */ + { .code = 0x78, .len = 5 }, /* 1: .---- */ + { .code = 0x38, .len = 5 }, /* 2: ..--- */ + { .code = 0x18, .len = 5 }, /* 3: ...-- */ + { .code = 0x08, .len = 5 }, /* 4: ....- */ + { .code = 0x00, .len = 5 }, /* 5: ..... */ + { .code = 0x80, .len = 5 }, /* 6: -.... */ + { .code = 0xc0, .len = 5 }, /* 7: --... */ + { .code = 0xe0, .len = 5 }, /* 8: ---.. */ + { .code = 0xf0, .len = 5 }, /* 9: ----. */ +}; + +/*! Symbol table: "letters" */ +static const struct morse_sym_table_t morse_letters[] = { + { .code = 0x40, .len = 2 }, /* A: .- */ + { .code = 0x80, .len = 4 }, /* B: -... */ + { .code = 0xa0, .len = 4 }, /* C: -.-. */ + { .code = 0x80, .len = 3 }, /* D: -.. */ + { .code = 0x00, .len = 1 }, /* E: . */ + { .code = 0x20, .len = 4 }, /* F: ..-. */ + { .code = 0xc0, .len = 3 }, /* G: --. */ + { .code = 0x00, .len = 4 }, /* H: .... */ + { .code = 0x00, .len = 2 }, /* I: .. */ + { .code = 0x70, .len = 4 }, /* J: .--- */ + { .code = 0xa0, .len = 3 }, /* K: -.- */ + { .code = 0x40, .len = 4 }, /* L: .-.. */ + { .code = 0xc0, .len = 2 }, /* M: -- */ + { .code = 0x80, .len = 2 }, /* N: -. */ + { .code = 0xe0, .len = 3 }, /* O: --- */ + { .code = 0x60, .len = 4 }, /* P: .--. */ + { .code = 0xd0, .len = 4 }, /* Q: --.- */ + { .code = 0x40, .len = 3 }, /* R: .-. */ + { .code = 0x00, .len = 3 }, /* S: ... */ + { .code = 0x80, .len = 1 }, /* T: - */ + { .code = 0x20, .len = 3 }, /* U: ..- */ + { .code = 0x10, .len = 4 }, /* V: ...- */ + { .code = 0x60, .len = 3 }, /* W: .-- */ + { .code = 0x90, .len = 4 }, /* X: -..- */ + { .code = 0xb0, .len = 4 }, /* Y: -.-- */ + { .code = 0xc0, .len = 4 }, /* Z: --.. */ +}; + +static void morse_next_sym(struct morse_player_t* const morse_player) +{ + struct sfx_player_t* sfx_player = &(morse_player->sfx_player); + + if (!morse_player->msg) { + sfx_play(sfx_player, NULL); + return; + } + + uint8_t sym_rem = 0; + uint8_t sym_code = 0; + const struct morse_sym_table_t* sym = NULL; + const char* c = morse_player->msg; + + while(!sym) { + if ((*c >= 'A') && (*c <= 'Z')) + /* Play a letter. (capitals) */ + sym = &morse_letters[*c - 'A']; + else if ((*c >= 'a') && (*c <= 'z')) + /* Play a letter. (lowercase) */ + sym = &morse_letters[*c - 'a']; + else if ((*c >= '0') && (*c <= '9')) + /* Play a digit. */ + sym = &morse_digits[*c - '0']; + else if (*c == 0) { + morse_player->msg = NULL; + return; + } + c++; + } + morse_player->msg = c; + + struct sfx_note_t* note = morse_player->sym; + sym_rem = sym->len; + sym_code = sym->code; + + while(sym_rem) { + note->freq = morse_player->freq; + if (sym_code & 0x80) + /* Play a "dah" */ + note->duration = morse_player->dit_time*3; + else + /* Play a "dit" */ + note->duration = morse_player->dit_time; + note++; + sym_code <<= 1; + sym_rem--; + + /* A gap follows */ + note->freq = 0; + + if (sym_rem) { + /* More of the character */ + note->duration = morse_player->dit_time; + note++; + } + } + + /* What comes next? */ + if (*c == ' ') { + /* End of word */ + note->duration = morse_player->dit_time*7; + note++; + } else if (*c) { + /* End of character */ + note->duration = morse_player->dit_time*3; + note++; + } + + /* Terminate the sequence */ + note->freq = 0; + note->duration = 0; + + /* Set the player up */ + sfx_play(sfx_player, morse_player->sym); +} + +/*! + * Start playing a particular effect. + * @param sfx_player Effect player state machine + * @param effect Pointer to sound effect (NULL == stop) + */ +void morse_play(struct morse_player_t* const morse_player, + const char* msg) +{ + morse_player->msg = msg; + morse_next_sym(morse_player); +} + +/*! + * Retrieve the next sample to be played. + */ +int16_t morse_next(struct morse_player_t* const morse_player) +{ + if (!morse_player) + return(0); + if (!morse_player->sfx_player.note) + morse_next_sym(morse_player); + return sfx_next(&(morse_player->sfx_player)); +} diff --git a/stm32/src/sfx.c b/stm32/src/sfx.c new file mode 100644 index 0000000..f80c8d1 --- /dev/null +++ b/stm32/src/sfx.c @@ -0,0 +1,67 @@ +/*! + * Sound effect player library. + * + * This implements a state machine for playing back various monophonic + * sound effects such as morse code symbols, clicks and alert tones. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include "sfx.h" + +static void sfx_next_tone(struct sfx_player_t* const sfx_player) +{ + struct tone_gen_t* tone_gen = &(sfx_player->tone_gen); + const struct sfx_note_t* note = sfx_player->note; + + if (!note) { + tone_reset(tone_gen, 0, 0); + } else { + tone_reset(tone_gen, note->freq, note->duration); + + if (!note->duration) + /* We are done */ + sfx_player->note = NULL; + else + /* Move to next note */ + sfx_player->note++; + } +} + +/*! + * Start playing a particular effect. + * @param sfx_player Effect player state machine + * @param effect Pointer to sound effect (NULL == stop) + */ +void sfx_play(struct sfx_player_t* const sfx_player, + const struct sfx_note_t* effect) +{ + sfx_player->note = effect; + sfx_next_tone(sfx_player); +} + +/*! + * Retrieve the next sample to be played. + */ +int16_t sfx_next(struct sfx_player_t* const sfx_player) +{ + if (!sfx_player) + return(0); + if (!sfx_player->tone_gen.remain) + sfx_next_tone(sfx_player); + return tone_next(&(sfx_player->tone_gen)); +} diff --git a/stm32/src/sm1000_leds_switches.c b/stm32/src/sm1000_leds_switches.c new file mode 100644 index 0000000..e8f6ffc --- /dev/null +++ b/stm32/src/sm1000_leds_switches.c @@ -0,0 +1,229 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: sm1000_leds_switches.c + AUTHOR......: David Rowe + DATE CREATED: 18 July 2014 + + Functions for controlling LEDs and reading switches on the SM1000. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#define _CPTT GPIO_Pin_10 +#define LED_PWR GPIO_Pin_12 +#define LED_PTT GPIO_Pin_13 +#define LED_RT GPIO_Pin_14 +#define LED_ERR GPIO_Pin_15 +#define SWITCH_PTT GPIO_Pin_7 +#define SWITCH_SELECT GPIO_Pin_0 +#define SWITCH_BACK GPIO_Pin_1 +#define EXT_PTT GPIO_Pin_8 + +#include <stm32f4xx.h> +#include <stm32f4xx_gpio.h> +#include "sm1000_leds_switches.h" + +void sm1000_leds_switches_init(void) { + GPIO_InitTypeDef GPIO_InitStruct; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + /* output pins */ + + GPIO_InitStruct.GPIO_Pin = LED_PWR | LED_PTT | LED_RT | LED_ERR | _CPTT; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* input pins */ + + GPIO_InitStruct.GPIO_Pin = SWITCH_PTT | SWITCH_SELECT | SWITCH_BACK; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; /* we have our own external pull ups */ + GPIO_Init(GPIOD, &GPIO_InitStruct); + + GPIO_InitStruct.GPIO_Pin = EXT_PTT; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; /* use internal pull up */ + GPIO_Init(GPIOD, &GPIO_InitStruct); + + +} + +void led_pwr(int state) { + if (state > 0) + GPIOD->ODR |= (1 << 12); + else if (state < 0) + GPIOD->ODR ^= (1 << 12); + else + GPIOD->ODR &= ~(1 << 12); +} + +void led_ptt(int state) { + if (state > 0) + GPIOD->ODR |= (1 << 13); + else if (state < 0) + GPIOD->ODR |= (1 << 13); + else + GPIOD->ODR &= ~(1 << 13); +} + +void led_rt(int state) { + if (state > 0) + GPIOD->ODR |= (1 << 14); + else if (state < 0) + GPIOD->ODR ^= (1 << 14); + else + GPIOD->ODR &= ~(1 << 14); +} + +void led_err(int state) { + if (state > 0) + GPIOD->ODR |= (1 << 15); + else if (state < 0) + GPIOD->ODR ^= (1 << 15); + else + GPIOD->ODR &= ~(1 << 15); +} + +void not_cptt(int state) { + if (state) + GPIOD->ODR |= (1 << 10); + else + GPIOD->ODR &= ~(1 << 10); +} + +int switch_ptt(void) { + return GPIOD->IDR & (1 << 7); +} + +int switch_select(void) { + return GPIOD->IDR & (1 << 0); +} + +int switch_back(void) { + return GPIOD->IDR & (1 << 1); +} + +int ext_ptt(void) { + return GPIOD->IDR & (1 << 8); +} + +/* + FUNCTION: ColorfulRingOfDeath() + AUTHOR..: xenovacivus + + Colourful ring of death, blink LEDs like crazy forever if something + really nasty happens. Adapted from USB Virtual COM Port (VCP) + module adapted from code I found here: + + https://github.com/xenovacivus/STM32DiscoveryVCP + + Call this to indicate a failure. Blinks the STM32F4 discovery LEDs + in sequence. At 168Mhz, the blinking will be very fast - about 5 + Hz. Keep that in mind when debugging, knowing the clock speed + might help with debugging. +*/ + +int mycode; /* examine this with debugger if it dies */ + +void ColorfulRingOfDeath(int code) { + mycode = code; + uint16_t ring = 1; + while (1) { + uint32_t count = 0; + while (count++ < 5000000); + + GPIOD->BSRRH = (ring << 12); + ring = ring << 1; + if (ring >= 1<<4) { + ring = 1; + } + GPIOD->BSRRL = (ring << 12); + } +} +void HardFault_Handler(void) { ColorfulRingOfDeath(1); } +void MemManage_Handler(void) { ColorfulRingOfDeath(2); } +void BusFault_Handler(void) { ColorfulRingOfDeath(3); } +void UsageFault_Handler(void){ ColorfulRingOfDeath(4); } + + +void switch_tick(struct switch_t* const sw) +{ + if (sw->sw != sw->raw) { + /* State transition, reset timer */ + if (sw->state == SW_STEADY) + sw->last = sw->sw; + sw->state = SW_DEBOUNCE; + sw->timer = DEBOUNCE_DELAY; + sw->sw = sw->raw; + } else if (sw->state == SW_DEBOUNCE) { + if (sw->timer > 0) { + /* Steady so far, keep waiting */ + sw->timer--; + } else { + /* Steady state reached */ + sw->state = SW_STEADY; + } + } else if (sw->sw) { + /* Hold state. Yes this will wrap, but who cares? */ + sw->timer++; + } +} + +void switch_update(struct switch_t* const sw, uint8_t state) +{ + sw->raw = state; + if (sw->raw == sw->sw) + return; + + if (sw->state == SW_STEADY) + sw->last = sw->sw; + sw->timer = DEBOUNCE_DELAY; + sw->sw = sw->raw; + sw->state = SW_DEBOUNCE; +} + +uint32_t switch_pressed(const struct switch_t* const sw) +{ + if ((sw->state == SW_STEADY) && sw->sw) + return sw->timer; + return 0; +} + +int switch_released(const struct switch_t* const sw) +{ + if (sw->state != SW_STEADY) + return 0; + if (!sw->last) + return 0; + if (sw->sw) + return 0; + return 1; +} + +void switch_ack(struct switch_t* const sw) +{ + if (sw->state == SW_STEADY) + sw->last = sw->sw; +} diff --git a/stm32/src/sm1000_leds_switches_ut.c b/stm32/src/sm1000_leds_switches_ut.c new file mode 100644 index 0000000..9209bfc --- /dev/null +++ b/stm32/src/sm1000_leds_switches_ut.c @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: sm1000_leds_switches_ut.c + AUTHOR......: David Rowe + DATE CREATED: August 5 2014 + + Unit Test program for the SM1000 switches and LEDs driver. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include "sm1000_leds_switches.h" + +int main(void) { + sm1000_leds_switches_init(); + + while(1) { + led_pwr(switch_select()); + led_ptt(switch_ptt()); + led_rt(switch_back()); + led_err(!switch_back()); + } +} + diff --git a/stm32/src/sm1000_main.c b/stm32/src/sm1000_main.c new file mode 100644 index 0000000..6e5ec3b --- /dev/null +++ b/stm32/src/sm1000_main.c @@ -0,0 +1,1476 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: sm1000_main.c + AUTHOR......: David Rowe + DATE CREATED: August 5 2014 + + Main program for SM1000. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stm32f4_adc.h" +#include "stm32f4_dac.h" +#include "stm32f4_vrom.h" +#include "stm32f4_usart.h" +#include "freedv_api.h" +#include "codec2_fdmdv.h" +#include "sm1000_leds_switches.h" +#include "memtools.h" +#include <assert.h> +#include <stm32f4xx_gpio.h> +#include <stm32f4xx_rcc.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "sfx.h" +#include "sounds.h" +#include "morse.h" +#include "menu.h" +#include "tot.h" + +#define VERSION "V5" +#define FORTY_MS_16K (0.04*16000) /* 40ms of samples at 16 kHz */ +#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES) +#define CCM (void*)0x10000000 /* start of 64k CCM memory */ +#define CCM_LEN 0x10000 /* start of 64k CCM memory */ + +#define MENU_LED_PERIOD 100 +#define ANNOUNCE_DELAY 1500 +#define HOLD_DELAY 1000 +#define MENU_DELAY 1000 + +#define STATE_RX 0x00 /*!< Receive state: normal operation */ +#define STATE_TX 0x10 /*!< Transmit state: normal operation */ +#define STATE_RX_TOT 0x01 /*!< Receive state: after time-out */ +#define STATE_MENU 0x20 /*!< Menu state: normal operation */ + +/*! + * State machine states. We consider our state depending on what events + * are in effect at the start of the main() loop. For buttons, we have + * the following events: + * + * PRESS: Short-succession down-and-up event. (<1 second) + * DOWN: Button press event with no release. + * UP: Button release event. + * HOLD: Button press for a minimum duration of 1 second without + * release. + * + * We also have some other state machines: + * TOT: + * IDLE: No time-out event + * WARN: Warning period reached event + * WARN_TICK: Next warning tick due event + * TIMEOUT: Cease transmit event + * + * We consider ourselves to be in one of a few finite states: + * + * STATE_RX: Normal receive state. + * Conditions: !PTT.DOWN, !SELECT.HOLD + * + * We receive samples via the TRX ADC and pass those + * to SPEAKER DAC after demodulation/filtering. + * + * On SELECT.HOLD: go to STATE_MENU + * On SELECT.PRESS: next mode, stay in STATE_RX + * On BACK.PRESS: prev mode, stay in STATE_RX + * On PTT.DOWN: reset TOT, go to STATE_TX + * + * STATE_TX: Normal transmit state. + * Conditions: PTT.DOWN, !TOT.TIMEOUT + * + * We receive samples via the MIC ADC and pass those + * to TRX DAC after modulation/filtering. + * + * On PTT.UP: reset TOT, go to STATE_RX + * On TOT.WARN_TICK: play tick noise, + * reset WARN_TICK event, + * stay in STATE_TX + * On TOT.TIMEOUT: play timeout tune, + * reset TIMEOUT event + * go to STATE_RX_TOT. + * + * STATE_RX_TOT: Receive after time-out state. + * Conditions: PTT.DOWN + * + * We receive samples via the TRX ADC and pass those + * to SPEAKER DAC after demodulation/filtering. + * + * On PTT.UP: reset TOT, go to STATE_RX + * + * STATE_MENU: Menu operation state. Operation is dictated by + * the menu state machine, when we exit that state + * machine, we return to STATE_RX. + * + * On SELECT.HOLD: select the current menu entry, + * if it is a submenu then make that the current level + * On SELECT.PRESS: next entry in the current menu level + * On BACK.PRESS: prev mode in the current menu level + * On BACK.HOLD: go up to the previous menu + * save any changes to NV memory + * This may exit the menu system + * On PTT.DOWN: Exit menu system, do not save to NVM + * + * See the "Menu data" section of this file for the menu structure + * + */ +uint8_t core_state = STATE_RX; + +#define MAX_MODES 4 +#define ANALOG 0 +#define DV1600 1 +#define DV700D 2 +#define DV700E 3 + +struct switch_t sw_select; /*!< Switch driver for SELECT button */ +struct switch_t sw_back; /*!< Switch driver for BACK button */ +struct switch_t sw_ptt; /*!< Switch driver for PTT buttons */ + +struct tot_t tot; /*!< Time-out timer */ + +unsigned int announceTicker = 0; +unsigned int menuLEDTicker = 0; +unsigned int menuTicker = 0; +unsigned int menuExit = 0; + +uint32_t ms = 0; /* increments once per ms */ + +/*! + * User preferences + */ +static struct prefs_t { + /*! Serial number */ + uint64_t serial; + /*! Time-out timer period, in seconds increment */ + uint16_t tot_period; + /*! Time-out timer warning period, in seconds increment */ + uint16_t tot_warn_period; + /*! Menu frequency */ + uint16_t menu_freq; + /*! Menu speed */ + uint8_t menu_speed; + /*! Menu volume (attenuation) */ + uint8_t menu_vol; + /*! Default operating mode */ + uint8_t op_mode; +} prefs; + +/*! Preferences changed flag */ +int prefs_changed = 0; + +/*! Number of preference images kept */ +#define PREFS_IMG_NUM (2) +/*! Base ROM ID for preferences */ +#define PREFS_IMG_BASE (0) +/*! Minimum serial number */ +#define PREFS_SERIAL_MIN 8 +/*! Maximum serial number */ +#define PREFS_SERIAL_MAX UINT64_MAX + +/*! Preference serial numbers, by slot */ +static uint64_t prefs_serial[PREFS_IMG_NUM]; + +struct tone_gen_t tone_gen; +struct sfx_player_t sfx_player; +struct morse_player_t morse_player; + +void SysTick_Handler(void); + +/*! Menu item root */ +static const struct menu_item_t menu_root; + +#define MENU_EVT_NEXT 0x10 /*!< Increment the current item */ +#define MENU_EVT_PREV 0x11 /*!< Decrement the current item */ +#define MENU_EVT_SELECT 0x20 /*!< Select current item */ +#define MENU_EVT_BACK 0x21 /*!< Go back one level */ +#define MENU_EVT_EXIT 0x30 /*!< Exit menu */ + +/*! + * Software-mix two 16-bit samples. + */ +int16_t software_mix(int16_t a, int16_t b) { + int32_t s = a + b; + if (s < INT16_MIN) + return INT16_MIN; /* Clip! */ + if (s > INT16_MAX) + return INT16_MAX; /* Clip! */ + return s; +} + +/*! Compare current serial with oldest and newest */ +void compare_prefs(int* const oldest, int* const newest, int idx) +{ + if (newest && prefs_serial[idx]) { + if ((*newest < 0) + || (prefs_serial[idx] > prefs_serial[*newest]) + || ((prefs_serial[idx] == PREFS_SERIAL_MIN) + && (prefs_serial[*newest] == PREFS_SERIAL_MAX))) + *newest = idx; + } + + if (oldest) { + if ((*oldest < 0) + || (!prefs_serial[idx]) + || (prefs_serial[idx] < prefs_serial[*oldest]) + || ((prefs_serial[idx] == PREFS_SERIAL_MAX) + && (prefs_serial[*oldest] == PREFS_SERIAL_MIN))) + *oldest = idx; + } +} + +/*! Find oldest and newest images */ +void find_prefs(int* const oldest, int* const newest) +{ + int i; + if (newest) *newest = -1; + if (oldest) *oldest = -1; + for (i = 0; i < PREFS_IMG_NUM; i++) + compare_prefs(oldest, newest, i); +} + +/*! Load preferences from flash */ +int load_prefs() +{ + struct prefs_t image[PREFS_IMG_NUM]; + int newest = -1; + int i; + + /* Load all copies into RAM */ + for (i = 0; i < PREFS_IMG_NUM; i++) { + int res = vrom_read(PREFS_IMG_BASE + i, 0, + sizeof(image[i]), &image[i]); + if (res == sizeof(image[i])) { + prefs_serial[i] = image[i].serial; + compare_prefs(NULL, &newest, i); + } else { + prefs_serial[i] = 0; + } + } + + if (newest < 0) + /* No newest image was found */ + return -ENOENT; + + /* Load from the latest image */ + memcpy(&prefs, &image[newest], sizeof(prefs)); + return 0; +} + +void print_prefs(struct prefs_t *prefs) { + usart_printf("serial: %d\n", (int)prefs->serial); + usart_printf("tot_period: %d\n", (int)prefs->tot_period); + usart_printf("tot_warn_period: %d\n", (int)prefs->tot_warn_period); + usart_printf("menu_freq: %d\n", (int)prefs->menu_freq); + usart_printf("menu_speed: %d\n", (int)prefs->menu_speed); + usart_printf("menu_vol: %d\n", (int)prefs->menu_vol); + usart_printf("op_mode: %d\n", (int)prefs->op_mode); + usart_printf("prefs_changed: %d\n", prefs_changed); +} + +struct freedv *set_freedv_mode(int op_mode, int *n_samples) { + struct freedv *f = NULL; + switch(op_mode) { + case ANALOG: + usart_printf("Analog\n"); + *n_samples = FORTY_MS_16K/4; + f = NULL; + break; + case DV1600: + usart_printf("FreeDV 1600\n"); + f = freedv_open(FREEDV_MODE_1600); + assert(f != NULL); + *n_samples = freedv_get_n_speech_samples(f); + break; + case DV700D: + usart_printf("FreeDV 700D\n"); + f = freedv_open(FREEDV_MODE_700D); + assert(f != NULL); + freedv_set_snr_squelch_thresh(f, -2.0); /* squelch at -2.0 dB */ + freedv_set_squelch_en(f, 1); + freedv_set_eq(f, 1); /* equaliser on by default */ + + /* Clipping and TXBPF nice to have for 700D. */ + freedv_set_clip(f, 1); + freedv_set_tx_bpf(f, 1); + + *n_samples = freedv_get_n_speech_samples(f); + break; + case DV700E: + usart_printf("FreeDV 700E\n"); + f = freedv_open(FREEDV_MODE_700E); + assert(f != NULL); + freedv_set_snr_squelch_thresh(f, 0.0); /* squelch at 0.0 dB */ + freedv_set_squelch_en(f, 1); + freedv_set_eq(f, 1); /* equaliser on by default */ + + /* Clipping and TXBPF needed for 700E. */ + freedv_set_clip(f, 1); + freedv_set_tx_bpf(f, 1); + + *n_samples = freedv_get_n_speech_samples(f); + break; + } + return f; +} + +int process_core_state_machine(int core_state, struct menu_t *menu, int *op_mode); + +int main(void) { + struct freedv *f; + int nin, nout, i; + int n_samples, n_samples_16k; + + usart_init(); usart_printf("SM1000 VERSION: %s\n", VERSION); + usart_printf("SM1000 main()... stack 0x%x (%d)\n", &n_samples_16k, (uint32_t)0x2001ffff - (uint32_t)&n_samples_16k); + memtools_find_unused(usart_printf); + + /* Menu data */ + struct menu_t menu; + + /* Outgoing sample counter */ + int spk_nsamples = 0; + + /* Current runtime operation mode */ + int op_mode = ANALOG; + + /* init all the drivers for various peripherals */ + + SysTick_Config(SystemCoreClock/1000); /* 1 kHz SysTick */ + sm1000_leds_switches_init(); + + /* Enable CRC clock */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE); + + /* Briefly open FreeDV 700D to determine buffer sizes we need + (700D has the largest buffers) */ + + f = freedv_open(FREEDV_MODE_700D); + int n_speech_samples = freedv_get_n_speech_samples(f); + int n_speech_samples_16k = 2*n_speech_samples; + int n_modem_samples = freedv_get_n_max_modem_samples(f); + int n_modem_samples_16k = 2*n_modem_samples; + freedv_close(f); f = NULL; + usart_printf("n_speech_samples: %d n_modem_samples: %d\n", + n_speech_samples, n_modem_samples); + + /* both speech and modem buffers will be about the same size, but + choose the largest and add a little extra padding */ + if (n_speech_samples_16k > n_modem_samples_16k) + n_samples_16k = n_speech_samples_16k; + else + n_samples_16k = n_modem_samples_16k; + n_samples_16k += FORTY_MS_16K; + usart_printf("n_samples_16k: %d storage for 4 FIFOs: %d bytes\n", + n_samples_16k, 4*2*n_samples_16k); + + /* Set up ADCs/DACs and their FIFOs, note storage is in CCM memory */ + short *pccm = CCM; + usart_printf("pccm before dac/adc open: %p\n", pccm); + n_samples = n_samples_16k/2; + dac_open(DAC_FS_16KHZ, n_samples_16k, pccm, pccm+n_samples_16k); + pccm += 2*n_samples_16k; + adc_open(ADC_FS_16KHZ, n_samples_16k, pccm, pccm+n_samples_16k); + pccm += 2*n_samples_16k; + usart_printf("pccm after dac/adc open: %p\n", pccm); + assert((void*)pccm < CCM+CCM_LEN); + + short *adc16k = pccm; pccm += FDMDV_OS_TAPS_16K+n_samples_16k; + short *dac16k = pccm; pccm += n_samples_16k; + short adc8k[n_samples]; + short dac8k[FDMDV_OS_TAPS_8K+n_samples]; + usart_printf("pccm after buffers: %p\n", pccm); + assert((void*)pccm < CCM+CCM_LEN); + + /* clear buffers */ + for(i=0; i<FDMDV_OS_TAPS_16K+n_samples_16k; i++) + adc16k[i] = 0; + for(i=0; i<n_samples_16k; i++) + dac16k[i] = 0; + for(i=0; i<n_samples; i++) + adc8k[i] = 0; + for(i=0; i<FDMDV_OS_TAPS_8K+n_samples; i++) + dac8k[i] = 0; + + usart_printf("drivers initialised...stack: %p\n", memtools_sp); + memtools_find_unused(usart_printf); + + /* put outputs into a known state */ + led_pwr(1); led_ptt(0); led_rt(0); led_err(0); not_cptt(1); + + if (!switch_back()) { + /* Play tone to acknowledge, wait for release */ + tone_reset(&tone_gen, 1200, 1000); + while(!switch_back()) { + int dac_rem = dac2_free(); + if (dac_rem) { + // TODO this might need fixing for larger FIFOs + if (dac_rem > n_samples_16k) + dac_rem = n_samples_16k; + + for (i = 0; i < dac_rem; i++) + dac16k[i] = tone_next(&tone_gen); + dac2_write(dac16k, dac_rem, 0); + } + if (!menuLEDTicker) { + menuLEDTicker = MENU_LED_PERIOD; + led_rt(LED_INV); + } + } + + /* Button released, do an EEPROM erase */ + for (i = 0; i < PREFS_IMG_NUM; i++) + vrom_erase(i + PREFS_IMG_BASE); + } + led_rt(LED_OFF); + tone_reset(&tone_gen, 0, 0); + tot_reset(&tot); + + usart_printf("loading preferences from flash....\n"); + + /* Try to load preferences from flash */ + if (load_prefs() < 0) { + usart_printf("loading default preferences....\n"); + /* Fail! Load defaults. */ + memset(&prefs, 0, sizeof(prefs)); + prefs.op_mode = ANALOG; + prefs.menu_vol = 2; + prefs.menu_speed = 60; /* 20 WPM */ + prefs.menu_freq = 800; + prefs.tot_period = 0; /* Disable time-out timer */ + prefs.tot_warn_period = 15; + } + print_prefs(&prefs); + + /* Set up time-out timer, 100msec ticks */ + tot.tick_period = 100; + tot.remain_warn_ticks = 10; + + /* Clear out switch states */ + memset(&sw_select, 0, sizeof(sw_select)); + memset(&sw_back, 0, sizeof(sw_back)); + memset(&sw_ptt, 0, sizeof(sw_ptt)); + + /* Clear out menu state */ + memset(&menu, 0, sizeof(menu)); + + morse_player.freq = prefs.menu_freq; + morse_player.dit_time = prefs.menu_speed; + morse_player.msg = NULL; + op_mode = prefs.op_mode; + + /* default op-mode */ + f = set_freedv_mode(op_mode, &n_samples); + n_samples_16k = 2*n_samples; + + /* play VERSION and op mode at start-up. Morse player can't queue + so we assemble a concatenated string here */ + char startup_announcement[16]; + if (op_mode == ANALOG) + snprintf(startup_announcement, 16, VERSION " ANA"); + else if (op_mode == DV1600) + snprintf(startup_announcement, 16, VERSION " 1600"); + else if (op_mode == DV700D) + snprintf(startup_announcement, 16, VERSION " 700D"); + else if (op_mode == DV700E) + snprintf(startup_announcement, 16, VERSION " 700E"); + morse_play(&morse_player, startup_announcement); + + usart_printf("entering main loop...\n"); + uint32_t lastms = ms; + while(1) { + /* Read switch states */ + switch_update(&sw_select, (!switch_select()) ? 1 : 0); + switch_update(&sw_back, (!switch_back()) ? 1 : 0); + switch_update(&sw_ptt, (switch_ptt() || (!ext_ptt())) ? 1 : 0); + + /* Update time-out timer state */ + tot_update(&tot); + + /* iterate core state machine based on switch events */ + int prev_op_mode = op_mode; + int prev_core_state = core_state; + core_state = process_core_state_machine(core_state, &menu, &op_mode); + + /* Acknowledge switch events */ + switch_ack(&sw_select); + switch_ack(&sw_back); + switch_ack(&sw_ptt); + + /* if mode has changed, re-open freedv */ + if (op_mode != prev_op_mode) { + usart_printf("Mode change prev_op_mode: %d op_mode: %d\n", prev_op_mode, op_mode); + if (f) { freedv_close(f); } f = NULL; + f = set_freedv_mode(op_mode, &n_samples); + n_samples_16k = 2*n_samples; + usart_printf("FreeDV f = 0x%x n_samples: %d n_samples_16k: %d\n", (int)f, n_samples, n_samples_16k); + + /* clear buffers */ + + for(i=0; i<FDMDV_OS_TAPS_16K+n_samples_16k; i++) + adc16k[i] = 0; + for(i=0; i<n_samples_16k; i++) + dac16k[i] = 0; + for(i=0; i<n_samples; i++) + adc8k[i] = 0; + for(i=0; i<FDMDV_OS_TAPS_8K+n_samples; i++) + dac8k[i] = 0; + } + + /* if we have moved from tx to rx reset sync state of rx so we re-start acquisition */ + if ((op_mode == DV1600) || (op_mode == DV700D) || (op_mode == DV700E)) + if ((prev_core_state == STATE_TX) && (core_state == STATE_RX)) + freedv_set_sync(f, FREEDV_SYNC_UNSYNC); + + /* perform signal processing based on core state */ + switch (core_state) { + case STATE_MENU: + if (!menuLEDTicker) { + led_pwr(LED_INV); + menuLEDTicker = MENU_LED_PERIOD; + } + break; + case STATE_TX: + /* Transmit -------------------------------------------------------------------------*/ + + /* ADC2 is the SM1000 microphone, DAC1 is the modulator signal we send to radio tx */ + + if (adc2_read(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) { + GPIOE->ODR = (1 << 3); + + /* clipping indicator */ + + led_err(0); + for (i=0; i<n_samples_16k; i++) { + if (abs(adc16k[FDMDV_OS_TAPS_16K+i]) > 28000) + led_err(1); + } + + fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples); + + if (op_mode == ANALOG) { + for(i=0; i<n_samples; i++) + dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i]; + fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); + dac1_write(dac16k, n_samples_16k, 0); + } + else { + freedv_tx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k); + for(i=0; i<n_samples; i++) + dac8k[FDMDV_OS_TAPS_8K+i] *= 0.398; /* 8dB back off from peak */ + fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); + dac1_write(dac16k, n_samples_16k, 0); + } + + led_ptt(1); led_rt(0); led_err(0); not_cptt(0); + GPIOE->ODR &= ~(1 << 3); + } + break; + + case STATE_RX: + case STATE_RX_TOT: + /* Receive --------------------------------------------------------------------------*/ + + not_cptt(1); + led_ptt(0); + + /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */ + + if (op_mode == ANALOG) { + if (ms > lastms+5000) { + usart_printf("Analog\n"); + lastms = ms; + } + + if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) { + fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples); + for(i=0; i<n_samples; i++) + dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i]; + fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); + spk_nsamples = n_samples_16k; + led_rt(0); led_err(0); + } + } + else { + if (ms > lastms+5000) { + usart_printf("Digital Voice\n"); + lastms = ms; + } + + /* 1600 or 700D/E DV mode */ + + nin = freedv_nin(f); + nout = nin; + freedv_set_total_bit_errors(f, 0); + if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], 2*nin) == 0) { + GPIOE->ODR = (1 << 3); + fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin); + nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k); + fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout); + spk_nsamples = 2*nout; + led_rt(freedv_get_sync(f)); led_err(freedv_get_total_bit_errors(f)); + GPIOE->ODR &= ~(1 << 3); + } + } + break; + default: + break; + } + + /* Write audio to speaker output */ + if (spk_nsamples || sfx_player.note || morse_player.msg) { + /* Make a note of our playback position */ + int16_t* play_ptr = dac16k; + + if (!spk_nsamples) + spk_nsamples = dac2_free(); + + /* + * There is audio to play on the external speaker. If there + * is a sound or announcement, software-mix it into the outgoing + * buffer. + */ + if (sfx_player.note) { + int i; + if (menu.stack_depth) { + /* Exclusive */ + for (i = 0; i < spk_nsamples; i++) + dac16k[i] = sfx_next(&sfx_player) >> prefs.menu_vol; + } else { + /* Software mix */ + for (i = 0; i < spk_nsamples; i++) + dac16k[i] = software_mix(dac16k[i], + sfx_next(&sfx_player) >> prefs.menu_vol); + } + if (!sfx_player.note && morse_player.msg) + announceTicker = ANNOUNCE_DELAY; + } else if (!announceTicker && morse_player.msg) { + int i; + if (menu.stack_depth) { + for (i = 0; i < spk_nsamples; i++) + dac16k[i] = morse_next(&morse_player) >> prefs.menu_vol; + } else { + for (i = 0; i < spk_nsamples; i++) + dac16k[i] = software_mix(dac16k[i], + morse_next(&morse_player) >> prefs.menu_vol); + } + } + + while (spk_nsamples) { + /* Get the number of samples to be played this time around */ + int n_rem = dac2_free(); + if (spk_nsamples < n_rem) + n_rem = spk_nsamples; + /* Play the audio */ + dac2_write(play_ptr, n_rem, 0); + spk_nsamples -= n_rem; + play_ptr += n_rem; + } + + /* Clear out buffer */ + memset(dac16k, 0, n_samples_16k*sizeof(short)); + } + + } /* while(1) ... */ +} + +/* + * SysTick Interrupt Handler + */ + +void SysTick_Handler(void) +{ + ms++; + switch_tick(&sw_select); + switch_tick(&sw_back); + switch_tick(&sw_ptt); + if (menuTicker > 0) { + menuTicker--; + } + if (menuLEDTicker > 0) { + menuLEDTicker--; + } + if (announceTicker > 0) { + announceTicker--; + } + tot_tick(&tot); +} + + +int process_core_state_machine(int core_state, struct menu_t *menu, int *op_mode) { + /* State machine updates */ + switch(core_state) { + case STATE_RX: + { + uint8_t mode_changed = 0; + + if (!menuTicker) { + if (menuExit) { + /* We've just exited a menu, wait for release of BACK */ + if (switch_released(&sw_back)) + menuExit = 0; + } else if (switch_pressed(&sw_ptt)) { + /* Cancel any announcement if scheduled */ + if (announceTicker && morse_player.msg) { + announceTicker = 0; + morse_play(&morse_player, NULL); + } + /* Start time-out timer if enabled */ + if (prefs.tot_period) + tot_start(&tot, prefs.tot_period*10, + prefs.tot_warn_period*10); + /* Enter transmit state */ + core_state = STATE_TX; + } else if (switch_pressed(&sw_select) > HOLD_DELAY) { + /* Enter the menu */ + led_pwr(1); led_ptt(0); led_rt(0); + led_err(0); not_cptt(1); + + menu_enter(menu, &menu_root); + menuTicker = MENU_DELAY; + core_state = STATE_MENU; + prefs_changed = 0; + usart_printf("Entering menu ...\n"); + print_prefs(&prefs); + + } else if (switch_released(&sw_select)) { + /* Shortcut: change current mode */ + *op_mode = (*op_mode + 1) % MAX_MODES; + mode_changed = 1; + } else if (switch_released(&sw_back)) { + /* Shortcut: change current mode */ + *op_mode = *op_mode - 1; + if (*op_mode < 0) + { + // Loop back around to the end of the mode list if we reach 0. + *op_mode = MAX_MODES - 1; + } + mode_changed = 1; + } + + if (mode_changed) { + /* Announce the new mode */ + if (*op_mode == ANALOG) + morse_play(&morse_player, "ANA"); + else if (*op_mode == DV1600) + morse_play(&morse_player, "1600"); + else if (*op_mode == DV700D) + morse_play(&morse_player, "700D"); + else if (*op_mode == DV700E) + morse_play(&morse_player, "700E"); + sfx_play(&sfx_player, sound_click); + } + } + } + break; + case STATE_TX: + { + if (!switch_pressed(&sw_ptt)) { + /* PTT released, leave transmit mode */ + tot_reset(&tot); + core_state = STATE_RX; + } else if (tot.event & TOT_EVT_TIMEOUT) { + /* Time-out reached */ + sfx_play(&sfx_player, sound_death_march); + tot.event &= ~TOT_EVT_TIMEOUT; + core_state = STATE_RX_TOT; + } else if (tot.event & TOT_EVT_WARN_NEXT) { + /* Re-set warning flag */ + tot.event &= ~TOT_EVT_WARN_NEXT; + /* Schedule a click tone */ + sfx_play(&sfx_player, sound_click); + } + } + break; + case STATE_RX_TOT: + if (switch_released(&sw_ptt)) { + /* PTT released, leave transmit mode */ + tot_reset(&tot); + core_state = STATE_RX; + } + break; + case STATE_MENU: + if (!menuTicker) { + /* We are in a menu */ + static uint8_t press_ack = 0; + uint8_t save_settings = 0; + + if (press_ack == 1) { + if ((sw_select.state == SW_STEADY) + && (!sw_select.sw)) + press_ack = 0; + } else if (press_ack == 2) { + if ((sw_back.state == SW_STEADY) + && (!sw_back.sw)) + press_ack = 0; + } else { + if (switch_pressed(&sw_select) > HOLD_DELAY) { + menu_exec(menu, MENU_EVT_SELECT); + press_ack = 1; + menuTicker = MENU_DELAY; + } else if (switch_pressed(&sw_back) > HOLD_DELAY) { + menu_exec(menu, MENU_EVT_BACK); + press_ack = 2; + menuTicker = MENU_DELAY; + + usart_printf("Leaving menu ... stack_depth: %d \n", menu->stack_depth); + print_prefs(&prefs); + if (!menu->stack_depth) + save_settings = prefs_changed; + + } else if (switch_released(&sw_select)) { + menu_exec(menu, MENU_EVT_NEXT); + menuTicker = MENU_DELAY; + } else if (switch_released(&sw_back)) { + menu_exec(menu, MENU_EVT_PREV); + menuTicker = MENU_DELAY; + } else if (switch_released(&sw_ptt)) { + while(menu->stack_depth > 0) + menu_exec(menu, MENU_EVT_EXIT); + sfx_play(&sfx_player, sound_returned); + } + + /* If exited, put the LED back */ + if (!menu->stack_depth) { + menuLEDTicker = 0; + menuTicker = 0; + led_pwr(LED_ON); + morse_play(&morse_player, NULL); + menuExit = 1; + if (save_settings) { + int oldest = -1; + int res; + /* Copy the morse settings in */ + prefs.menu_freq = morse_player.freq; + prefs.menu_speed = morse_player.dit_time; + /* make sure we have same op mode as power on prefs */ + *op_mode = prefs.op_mode; + /* Increment serial number */ + prefs.serial++; + /* Find the oldest image */ + find_prefs(&oldest, NULL); + if (oldest < 0) + oldest = 0; /* No current image */ + + /* Write new settings over it */ + usart_printf("vrom_write\n"); + res = vrom_write(oldest + PREFS_IMG_BASE, 0, + sizeof(prefs), &prefs); + if (res >= 0) + prefs_serial[oldest] = prefs.serial; + } + /* Go back to receive state */ + core_state = STATE_RX; + } + } + } + break; + default: + break; + } + + return core_state; +} + + +/* ---------------------------- Menu data --------------------------- + * + * MENU - + * |- "MODE" Select operating mode + * | |- "ANA" - Analog + * | |- "DV1600" - FreeDV 1600 + * | |- "DV700D" - FreeDV 700D + * | |- "DV700E" - FreeDV 700E + * | + * |- "TOT" Timer Out Timer options + * | |- "TIME" - Set timeout time (a sub menu) + * | | |- - SELECT.PRESS add 5 sec + * | | |- - BACK.PRESS subtracts 5 sec + * | | + * | |- "WARN" - Set warning time (a sub menu) + * | | |- - SELECT.PRESS add 5 sec + * | | |- - BACK.PRESS subtracts 5 sec + * | + * |- "UI" UI (morse code announcements) parameters + * | |- "FREQ" - Set tone + * | | |- - SELECT.PRESS add 50 Hz + * | | |- - BACK.PRESS subtracts 50 Hz + * | | + * | |- "WPMQ" - Set speed + * | | |- - SELECT.PRESS add 5 WPM + * | | |- - BACK.PRESS subtracts 5 WPM + * | | + * | |- "VOL" - Set volume + * | | |- - SELECT.PRESS -> quieter + * | | |- - BACK.PRESS -> louder + */ + +/*! + * Default handler for menu callback. + */ +static void menu_default_cb(struct menu_t* const menu, uint32_t event) +{ + /* Get the current menu item */ + const struct menu_item_t* item = menu_item(menu, 0); + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Choose first item */ + menu->current = 0; + case MENU_EVT_RETURNED: + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + menu->current = (menu->current + 1) % item->num_children; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (menu->current == 0) + { + menu->current = item->num_children - 1; + } + else + { + menu->current = menu->current - 1; + } + announce = 1; + break; + case MENU_EVT_SELECT: + /* Enter the sub-menu */ + menu_enter(menu, item->children[menu->current]); + break; + case MENU_EVT_BACK: + /* Exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Announce the label of the selected child */ + morse_play(&morse_player, + item->children[menu->current]->label); + } +} + +/* Root menu item forward declarations */ +static const struct menu_item_t* menu_root_children[]; +/* Root item definition */ +static const struct menu_item_t menu_root = { + .label = "MENU", + .event_cb = menu_default_cb, + .children = menu_root_children, + .num_children = 3, +}; + +/* Child declarations */ +static const struct menu_item_t menu_op_mode; +static const struct menu_item_t menu_tot; +static const struct menu_item_t menu_ui; +static const struct menu_item_t * menu_root_children[] = { + &menu_op_mode, + &menu_tot, + &menu_ui, +}; + + +/* Operation Mode menu forward declarations */ +static void menu_op_mode_cb(struct menu_t* const menu, uint32_t event); +static struct menu_item_t const* menu_op_mode_children[]; +/* Operation mode menu */ +static const struct menu_item_t menu_op_mode = { + .label = "MODE", + .event_cb = menu_op_mode_cb, + .children = menu_op_mode_children, + .num_children = 4, +}; +/* Children */ +static const struct menu_item_t menu_op_mode_analog = { + .label = "ANA", + .event_cb = NULL, + .children = NULL, + .num_children = 0, + .data = { + .ui = ANALOG, + }, +}; +static const struct menu_item_t menu_op_mode_dv1600 = { + .label = "1600", + .event_cb = NULL, + .children = NULL, + .num_children = 0, + .data = { + .ui = DV1600, + }, +}; +static const struct menu_item_t menu_op_mode_dv700D = { + .label = "700D", + .event_cb = NULL, + .children = NULL, + .num_children = 0, + .data = { + .ui = DV700D, + }, +}; +static const struct menu_item_t menu_op_mode_dv700E = { + .label = "700E", + .event_cb = NULL, + .children = NULL, + .num_children = 0, + .data = { + .ui = DV700E, + }, +}; +static struct menu_item_t const* menu_op_mode_children[] = { + &menu_op_mode_analog, + &menu_op_mode_dv1600, + &menu_op_mode_dv700D, + &menu_op_mode_dv700E, +}; +/* Callback function */ +static void menu_op_mode_cb(struct menu_t* const menu, uint32_t event) +{ + const struct menu_item_t* item = menu_item(menu, 0); + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Choose current item */ + switch(prefs.op_mode) { + case DV1600: + menu->current = 1; + break; + case DV700D: + menu->current = 2; + break; + case DV700E: + menu->current = 3; + break; + default: + menu->current = 0; + } + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + menu->current = (menu->current + 1) % item->num_children; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (menu->current == 0) + { + menu->current = item->num_children - 1; + } + else + { + menu->current = menu->current - 1; + } + announce = 1; + break; + case MENU_EVT_SELECT: + /* Choose the selected mode */ + prefs.op_mode = item->children[menu->current]->data.ui; + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + prefs_changed = 1; + menu_leave(menu); + break; + case MENU_EVT_BACK: + /* Exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Announce the label of the selected child */ + morse_play(&morse_player, + item->children[menu->current]->label); + } +} + + +/* Time-out timer menu forward declarations */ +static struct menu_item_t const* menu_tot_children[]; +/* Operation mode menu */ +static const struct menu_item_t menu_tot = { + .label = "TOT", + .event_cb = menu_default_cb, + .children = menu_tot_children, + .num_children = 2, +}; +/* Children */ +static const struct menu_item_t menu_tot_time; +static const struct menu_item_t menu_tot_warn; +static struct menu_item_t const* menu_tot_children[] = { + &menu_tot_time, + &menu_tot_warn, +}; + +/* TOT time menu forward declarations */ +static void menu_tot_time_cb(struct menu_t* const menu, uint32_t event); +/* TOT time menu */ +static const struct menu_item_t menu_tot_time = { + .label = "TIME", + .event_cb = menu_tot_time_cb, + .children = NULL, + .num_children = 0, +}; + +/* Callback function */ +static void menu_tot_time_cb(struct menu_t* const menu, uint32_t event) +{ + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Get the current period */ + menu->current = prefs.tot_period; + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + /* Adjust the frequency up by 50 Hz */ + if (prefs.tot_period < 600) + prefs.tot_period += 5; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (prefs.tot_period > 0) + prefs.tot_period -= 5; + announce = 1; + break; + case MENU_EVT_SELECT: + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + prefs_changed = 1; + menu_leave(menu); + break; + case MENU_EVT_BACK: + /* Restore the mode and exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + prefs.tot_period = menu->current; + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Render the text, thankfully we don't need re-entrancy */ + static char period[6]; + snprintf(period, 6, "%d", prefs.tot_period); + /* Announce the period */ + morse_play(&morse_player, period); + } +}; + +/* TOT warning time menu forward declarations */ +static void menu_tot_warn_cb(struct menu_t* const menu, uint32_t event); +/* TOT warning time menu */ +static const struct menu_item_t menu_tot_warn = { + .label = "WARN", + .event_cb = menu_tot_warn_cb, + .children = NULL, + .num_children = 0, +}; + +/* Callback function */ +static void menu_tot_warn_cb(struct menu_t* const menu, uint32_t event) +{ + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Get the current period */ + if (prefs.tot_warn_period < prefs.tot_period) + menu->current = prefs.tot_warn_period; + else + menu->current = prefs.tot_period; + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + /* Adjust the frequency up by 50 Hz */ + if (prefs.tot_warn_period < prefs.tot_period) + prefs.tot_warn_period += 5; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (prefs.tot_warn_period > 0) + prefs.tot_warn_period -= 5; + announce = 1; + break; + case MENU_EVT_SELECT: + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + prefs_changed = 1; + menu_leave(menu); + break; + case MENU_EVT_BACK: + /* Restore the mode and exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + prefs.tot_warn_period = menu->current; + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Render the text, thankfully we don't need re-entrancy */ + static char period[6]; + snprintf(period, 6, "%d", prefs.tot_warn_period); + /* Announce the period */ + morse_play(&morse_player, period); + } +}; + +/* UI menu forward declarations */ +static struct menu_item_t const* menu_ui_children[]; +/* Operation mode menu */ +static const struct menu_item_t menu_ui = { + .label = "UI", + .event_cb = menu_default_cb, + .children = menu_ui_children, + .num_children = 3, +}; +/* Children */ +static const struct menu_item_t menu_ui_freq; +static const struct menu_item_t menu_ui_speed; +static const struct menu_item_t menu_ui_vol; +static struct menu_item_t const* menu_ui_children[] = { + &menu_ui_freq, + &menu_ui_speed, + &menu_ui_vol, +}; + +/* UI Frequency menu forward declarations */ +static void menu_ui_freq_cb(struct menu_t* const menu, uint32_t event); +/* UI Frequency menu */ +static const struct menu_item_t menu_ui_freq = { + .label = "FREQ", + .event_cb = menu_ui_freq_cb, + .children = NULL, + .num_children = 0, +}; +/* Callback function */ +static void menu_ui_freq_cb(struct menu_t* const menu, uint32_t event) +{ + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Get the current frequency */ + menu->current = morse_player.freq; + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + /* Adjust the frequency up by 50 Hz */ + if (morse_player.freq < 2000) + morse_player.freq += 50; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (morse_player.freq > 50) + morse_player.freq -= 50; + announce = 1; + break; + case MENU_EVT_SELECT: + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + prefs_changed = 1; + menu_leave(menu); + break; + case MENU_EVT_BACK: + /* Restore the mode and exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + morse_player.freq = menu->current; + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Render the text, thankfully we don't need re-entrancy */ + static char freq[6]; + snprintf(freq, 6, "%d", morse_player.freq); + /* Announce the frequency */ + morse_play(&morse_player, freq); + } +}; + +/* UI Speed menu forward declarations */ +static void menu_ui_speed_cb(struct menu_t* const menu, uint32_t event); +/* UI Speed menu */ +static const struct menu_item_t menu_ui_speed = { + .label = "WPM", + .event_cb = menu_ui_speed_cb, + .children = NULL, + .num_children = 0, +}; +/* Callback function */ +static void menu_ui_speed_cb(struct menu_t* const menu, uint32_t event) +{ + uint8_t announce = 0; + + /* Get the current WPM */ + uint16_t curr_wpm = 1200 / morse_player.dit_time; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Get the current frequency */ + menu->current = morse_player.dit_time; + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + /* Increment WPM by 5 */ + if (curr_wpm < 60) + curr_wpm += 5; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (curr_wpm > 5) + curr_wpm -= 5; + announce = 1; + break; + case MENU_EVT_SELECT: + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + prefs_changed = 1; + menu_leave(menu); + break; + case MENU_EVT_BACK: + /* Restore the mode and exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + morse_player.dit_time = menu->current; + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Render the text, thankfully we don't need re-entrancy */ + static char wpm[5]; + snprintf(wpm, 5, "%d", curr_wpm); + /* Set the new parameter */ + morse_player.dit_time = 1200 / curr_wpm; + /* Announce the words per minute */ + morse_play(&morse_player, wpm); + } +}; + +/* UI volume menu forward declarations */ +static void menu_ui_vol_cb(struct menu_t* const menu, uint32_t event); +/* UI volume menu */ +static const struct menu_item_t menu_ui_vol = { + .label = "VOL", + .event_cb = menu_ui_vol_cb, + .children = NULL, + .num_children = 0, +}; +/* Callback function */ +static void menu_ui_vol_cb(struct menu_t* const menu, uint32_t event) +{ + uint8_t announce = 0; + + switch(event) { + case MENU_EVT_ENTERED: + sfx_play(&sfx_player, sound_startup); + /* Get the current volume */ + menu->current = prefs.menu_vol; + case MENU_EVT_RETURNED: + /* Shouldn't happen, but we handle it anyway */ + announce = 1; + break; + case MENU_EVT_NEXT: + sfx_play(&sfx_player, sound_click); + if (prefs.menu_vol > 0) + prefs.menu_vol--; + announce = 1; + break; + case MENU_EVT_PREV: + sfx_play(&sfx_player, sound_click); + if (prefs.menu_vol < 14) + prefs.menu_vol++; + announce = 1; + break; + case MENU_EVT_SELECT: + /* Play the "selected" tune and return. */ + sfx_play(&sfx_player, sound_startup); + menu_leave(menu); + prefs_changed = 1; + break; + case MENU_EVT_BACK: + /* Restore the mode and exit the menu */ + sfx_play(&sfx_player, sound_returned); + case MENU_EVT_EXIT: + prefs.menu_vol = menu->current; + menu_leave(menu); + break; + default: + break; + } + + if (announce) { + /* Render the text, thankfully we don't need re-entrancy */ + static char vol[5]; + snprintf(vol, 5, "%d", 15 - prefs.menu_vol); + /* Announce the volume level */ + morse_play(&morse_player, vol); + } +}; diff --git a/stm32/src/sounds.c b/stm32/src/sounds.c new file mode 100644 index 0000000..54848b8 --- /dev/null +++ b/stm32/src/sounds.c @@ -0,0 +1,62 @@ +/*! + * Sound effect library. + * + * This provides some sound effects for the SM1000 UI. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "sounds.h" + +const struct sfx_note_t sound_startup[] = { + {.freq = 600, .duration = 80}, + {.freq = 800, .duration = 80}, + {.freq = 1000, .duration = 80}, + {.freq = 0, .duration = 0} +}; + +const struct sfx_note_t sound_returned[] = { + {.freq = 1000, .duration = 80}, + {.freq = 800, .duration = 80}, + {.freq = 600, .duration = 80}, + {.freq = 0, .duration = 0} +}; + +const struct sfx_note_t sound_click[] = { + {.freq = 1200, .duration = 10}, + {.freq = 0, .duration = 0} +}; + +const struct sfx_note_t sound_death_march[] = { + {.freq = 340, .duration = 400}, + {.freq = 0, .duration = 80}, + {.freq = 340, .duration = 400}, + {.freq = 0, .duration = 80}, + {.freq = 340, .duration = 400}, + {.freq = 0, .duration = 80}, + {.freq = 420, .duration = 400}, + {.freq = 0, .duration = 80}, + {.freq = 400, .duration = 300}, + {.freq = 0, .duration = 80}, + {.freq = 340, .duration = 120}, + {.freq = 0, .duration = 80}, + {.freq = 340, .duration = 120}, + {.freq = 0, .duration = 80}, + {.freq = 300, .duration = 200}, + {.freq = 0, .duration = 80}, + {.freq = 340, .duration = 400}, + {.freq = 0, .duration = 0}, +}; diff --git a/stm32/src/startup_stm32f4xx.s b/stm32/src/startup_stm32f4xx.s new file mode 100644 index 0000000..6a34870 --- /dev/null +++ b/stm32/src/startup_stm32f4xx.s @@ -0,0 +1,526 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler +.global EndofMain + +/* 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 all memory from bss up */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Zero memory from bss up with a sentinel value */ + b LoopFillsentinel +Fillsentinel: + ldr r3, = 0x55555555 /* sentinel value we put in memory */ + str r3, [r2], #4 + +LoopFillsentinel: + ldr r3, = 0x2001fffc /* end of ram */ + cmp r2, r3 + bcc Fillsentinel + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main +EndofMain: + bl . +.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/stm32/src/stm32f4_adc.c b/stm32/src/stm32f4_adc.c new file mode 100644 index 0000000..96e776b --- /dev/null +++ b/stm32/src/stm32f4_adc.c @@ -0,0 +1,286 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_adc.c + AUTHOR......: David Rowe + DATE CREATED: 4 June 2013 + + Two channel ADC driver module for STM32F4. Pin PA1 connects to ADC1, pin + PA2 connects to ADC2. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "stm32f4xx_adc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_rcc.h" + +#include "codec2_fifo.h" +#include "stm32f4_adc.h" +#include "debugblinky.h" + +struct FIFO *adc1_fifo; +struct FIFO *adc2_fifo; +unsigned short adc_buf[ADC_BUF_SZ]; +int adc_overflow1, adc_overflow2; +int half,full; + +#define ADCx_DR_ADDRESS ((uint32_t)0x4001204C) +#define DMA_CHANNELx DMA_Channel_0 +#define DMA_STREAMx DMA2_Stream0 +#define ADCx ADC1 + +void adc_configure(); + +static void tim2_config(int fs_divisor); + +// You can optionally supply your own storage for the FIFO buffers bu1 and buf2, +// or set them to NULL and they will be malloc-ed for you +void adc_open(int fs_divisor, int fifo_sz, short *buf1, short *buf2) { + if (buf1 == NULL) { + adc1_fifo = codec2_fifo_create(fifo_sz); + adc2_fifo = codec2_fifo_create(fifo_sz); + } else { + adc1_fifo = codec2_fifo_create_buf(fifo_sz, buf1); + adc2_fifo = codec2_fifo_create_buf(fifo_sz, buf2); + } + + tim2_config(fs_divisor); + adc_configure(); + init_debug_blinky(); +} + +/* n signed 16 bit samples in buf[] if return != -1 */ + +int adc1_read(short buf[], int n) { + return codec2_fifo_read(adc1_fifo, buf, n); +} + +/* n signed 16 bit samples in buf[] if return != -1 */ + +int adc2_read(short buf[], int n) { + return codec2_fifo_read(adc2_fifo, buf, n); +} + +/* Returns number of signed 16 bit samples in the FIFO currently */ +int adc1_samps(){ + return codec2_fifo_used(adc1_fifo); +} + +/* Returns number of signed 16 bit samples in the FIFO currently */ +int adc2_samps(){ + return codec2_fifo_used(adc2_fifo); +} + +static void tim2_config(int fs_divisor) +{ + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + + /* TIM2 Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + + /* -------------------------------------------------------- + + TIM2 input clock (TIM2CLK) is set to 2 * APB1 clock (PCLK1), since + APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig + 13 clock tree figure in DM0031020.pdf). + + Sample rate Fs = 2*PCLK1/TIM_ClockDivision + = (HCLK/2)/TIM_ClockDivision + + ----------------------------------------------------------- */ + + /* Time base configuration */ + + TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); + TIM_TimeBaseStructure.TIM_Period = fs_divisor - 1; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + + /* TIM2 TRGO selection */ + + TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); + + /* TIM2 enable counter */ + + TIM_Cmd(TIM2, ENABLE); +} + + +void adc_configure(){ + ADC_InitTypeDef ADC_init_structure; + GPIO_InitTypeDef GPIO_initStructre; + DMA_InitTypeDef DMA_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + // Clock configuration + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOAEN,ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + + // Analog pin configuration ADC1->PA1, ADC2->PA2 + + GPIO_initStructre.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; + GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; + GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA,&GPIO_initStructre); + + // ADC structure configuration + + ADC_DeInit(); + ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Left; + ADC_init_structure.ADC_Resolution = ADC_Resolution_12b; + ADC_init_structure.ADC_ContinuousConvMode = DISABLE; + ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; + ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; + ADC_init_structure.ADC_NbrOfConversion = 2; + ADC_init_structure.ADC_ScanConvMode = ENABLE; + ADC_Init(ADCx,&ADC_init_structure); + + // Select the channel to be read from + + ADC_RegularChannelConfig(ADCx,ADC_Channel_1,1,ADC_SampleTime_144Cycles); + ADC_RegularChannelConfig(ADCx,ADC_Channel_2,2,ADC_SampleTime_144Cycles); + //ADC_VBATCmd(ENABLE); + + /* DMA configuration **************************************/ + + DMA_DeInit(DMA_STREAMx); + DMA_InitStructure.DMA_Channel = DMA_CHANNELx; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adc_buf; + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + DMA_InitStructure.DMA_BufferSize = ADC_BUF_SZ; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(DMA_STREAMx, &DMA_InitStructure); + + /* Enable DMA request after last transfer (Single-ADC mode) */ + + ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE); + + /* Enable ADC1 DMA */ + + ADC_DMACmd(ADCx, ENABLE); + + /* DMA2_Stream0 enable */ + + DMA_Cmd(DMA_STREAMx, ENABLE); + + /* Enable DMA Half & Complete interrupts */ + + DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE); + + /* Enable the DMA Stream IRQ Channel */ + + NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + // Enable and start ADC conversion + + ADC_Cmd(ADC1,ENABLE); + ADC_SoftwareStartConv(ADC1); +} + +/* + This function handles DMA Stream interrupt request. +*/ + +void DMA2_Stream0_IRQHandler(void) { + int i, j, sam; + short signed_buf1[ADC_BUF_SZ/2]; + short signed_buf2[ADC_BUF_SZ/2]; + + GPIOE->ODR |= (1 << 0); + + /* Half transfer interrupt */ + + if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0) != RESET) { + half++; + + /* convert to signed */ + + for(i=0, j=0; i<ADC_BUF_SZ/2; i+=2,j++) { + sam = (int)adc_buf[i] - 32768; + signed_buf1[j] = sam; + sam = (int)adc_buf[i+1] - 32768; + signed_buf2[j] = sam; + } + /* write first half to fifo */ + + if (codec2_fifo_write(adc1_fifo, signed_buf1, ADC_BUF_SZ/4) == -1) { + adc_overflow1++; + } + if (codec2_fifo_write(adc2_fifo, signed_buf2, ADC_BUF_SZ/4) == -1) { + adc_overflow2++; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0); + } + + /* Transfer complete interrupt */ + + if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET) { + full++; + + /* convert to signed */ + + for(i=0, j=0; i<ADC_BUF_SZ/2; i+=2,j++) { + sam = (int)adc_buf[ADC_BUF_SZ/2 + i] - 32768; + signed_buf1[j] = sam; + sam = (int)adc_buf[ADC_BUF_SZ/2 + i+1] - 32768; + signed_buf2[j] = sam; + } + + /* write second half to fifo */ + + if (codec2_fifo_write(adc1_fifo, signed_buf1, ADC_BUF_SZ/4) == -1) { + adc_overflow1++; + } + if (codec2_fifo_write(adc2_fifo, signed_buf2, ADC_BUF_SZ/4) == -1) { + adc_overflow2++; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); + } + + GPIOE->ODR &= ~(1 << 0); +} + diff --git a/stm32/src/stm32f4_dac.c b/stm32/src/stm32f4_dac.c new file mode 100644 index 0000000..ec61bf4 --- /dev/null +++ b/stm32/src/stm32f4_dac.c @@ -0,0 +1,427 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_dac.c + AUTHOR......: David Rowe + DATE CREATED: 1 June 2013 + + DAC driver module for STM32F4. DAC1 is connected to pin PA4, DAC2 + is connected to pin PA5. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "stm32f4xx.h" +#include "codec2_fifo.h" +#include "stm32f4_dac.h" +#include "debugblinky.h" + +/* write to these registers for 12 bit left aligned data, as per data sheet + make sure 4 least sig bits set to 0 */ + +#define DAC_DHR12R1_ADDRESS 0x40007408 +#define DAC_DHR12R2_ADDRESS 0x40007414 + +#define DAC_MAX 4096 /* maximum amplitude */ + +/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74 + of data sheet indicates With DAC buffer on, DAC range is limited to + 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close. + */ + +#define M ((3868.0-224.0)/65536.0) +#define C 2047.0 + +static struct FIFO *dac1_fifo; +static struct FIFO *dac2_fifo; + +static unsigned short dac1_buf[DAC_BUF_SZ]; +static unsigned short dac2_buf[DAC_BUF_SZ]; + +static void tim6_config(int fs_divisor); +static void dac1_config(void); +static void dac2_config(void); + +int dac_underflow; + +// You can optionally supply your own storage for the FIFO buffers bu1 and buf2, +// or set them to NULL and they will be malloc-ed for you +void dac_open(int fs_divisor, int fifo_size, short *buf1, short *buf2) { + + memset(dac1_buf, 32768, sizeof(short)*DAC_BUF_SZ); + memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ); + + /* Create fifos */ + + if ((buf1 == NULL) && (buf2 == NULL)) { + dac1_fifo = codec2_fifo_create(fifo_size); + dac2_fifo = codec2_fifo_create(fifo_size); + } else { + dac1_fifo = codec2_fifo_create_buf(fifo_size, buf1); + dac2_fifo = codec2_fifo_create_buf(fifo_size, buf2); + } + + /* Turn on the clocks we need -----------------------------------------------*/ + + /* DMA1 clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + /* GPIOA clock enable (to be used with DAC) */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + /* DAC Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/ + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/ + + tim6_config(fs_divisor); + dac1_config(); + dac2_config(); + + init_debug_blinky(); +} + +/* Call these functions to send samples to the DACs. For your + convenience they accept signed 16 bit samples. You can optionally + limit how much data to store in the fifo */ + +int dac1_write(short buf[], int n, int limit) { + /* artificial limit < FIFO size */ + if (limit) { + if ((codec2_fifo_used(dac1_fifo) + n) <= limit) + return codec2_fifo_write(dac1_fifo, buf, n); + else + return -1; + } + /* normal operation */ + return codec2_fifo_write(dac1_fifo, buf, n); +} + +int dac2_write(short buf[], int n, int limit) { + /* artificial limit < FIFO size */ + if (limit) { + if ((codec2_fifo_used(dac2_fifo) + n) <= limit) + return codec2_fifo_write(dac2_fifo, buf, n); + else + return -1; + } + /* normal operation */ + return codec2_fifo_write(dac2_fifo, buf, n); +} + +int dac1_free() { + return codec2_fifo_free(dac1_fifo); +} + +int dac2_free() { + return codec2_fifo_free(dac2_fifo); +} + +static void tim6_config(int fs_divisor) +{ + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + + /* TIM6 Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); + + /* -------------------------------------------------------- + + TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since + APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig + 13 clock tree figure in DM0031020.pdf). + + Sample rate Fs = 2*PCLK1/TIM_ClockDivision + = (HCLK/2)/TIM_ClockDivision + + ----------------------------------------------------------- */ + + /* Time base configuration */ + + TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); + TIM_TimeBaseStructure.TIM_Period = fs_divisor - 1; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); + + /* TIM6 TRGO selection */ + + TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); + + /* TIM6 enable counter */ + + TIM_Cmd(TIM6, ENABLE); +} + +static void dac1_config(void) +{ + DAC_InitTypeDef DAC_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* DAC channel 1 Configuration */ + + /* + This line fixed a bug that cost me 5 days, bad wave amplitude + value, and some STM32F4 periph library bugs caused triangle wave + geneartion to be enable resulting in a low level tone on the + SM1000, that we thought was caused by analog issues like layour + or power supply biasing + */ + DAC_StructInit(&DAC_InitStructure); + + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(DAC_Channel_1, &DAC_InitStructure); + + /* DMA1_Stream5 channel7 configuration **************************************/ + /* Table 35 page 219 of the monster data sheet */ + + DMA_DeInit(DMA1_Stream5); + DMA_InitStructure.DMA_Channel = DMA_Channel_7; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(DMA1_Stream5, &DMA_InitStructure); + + /* Enable DMA Half & Complete interrupts */ + + DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE); + + /* Enable the DMA Stream IRQ Channel */ + + NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Enable DMA1_Stream5 */ + + DMA_Cmd(DMA1_Stream5, ENABLE); + + /* Enable DAC Channel 1 */ + + DAC_Cmd(DAC_Channel_1, ENABLE); + + /* Enable DMA for DAC Channel 1 */ + + DAC_DMACmd(DAC_Channel_1, ENABLE); +} + +static void dac2_config(void) +{ + DAC_InitTypeDef DAC_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* DAC channel 2 Configuration (see notes in dac1_config() above) */ + + DAC_StructInit(&DAC_InitStructure); + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(DAC_Channel_2, &DAC_InitStructure); + + /* DMA1_Stream6 channel7 configuration **************************************/ + + DMA_DeInit(DMA1_Stream6); + DMA_InitStructure.DMA_Channel = DMA_Channel_7; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(DMA1_Stream6, &DMA_InitStructure); + + /* Enable DMA Half & Complete interrupts */ + + DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE); + + /* Enable the DMA Stream IRQ Channel */ + + NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Enable DMA1_Stream6 */ + + DMA_Cmd(DMA1_Stream6, ENABLE); + + /* Enable DAC Channel 2 */ + + DAC_Cmd(DAC_Channel_2, ENABLE); + + /* Enable DMA for DAC Channel 2 */ + + DAC_DMACmd(DAC_Channel_2, ENABLE); + +} + +/******************************************************************************/ +/* STM32F4xx 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_stm32f40xx.s/startup_stm32f427x.s). */ +/******************************************************************************/ + +/* + This function handles DMA1 Stream 5 interrupt request for DAC1. +*/ + +void DMA1_Stream5_IRQHandler(void) { + int i, j, sam; + short signed_buf[DAC_BUF_SZ/2]; + + GPIOE->ODR |= (1 << 1); + + /* Transfer half empty interrupt - refill first half */ + + if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) { + /* fill first half from fifo */ + + if (codec2_fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + /* convert to unsigned */ + + for(i=0; i<DAC_BUF_SZ/2; i++) { + sam = (int)(M*(float)signed_buf[i] + C); + dac1_buf[i] = (unsigned short)sam; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5); + } + + /* Transfer complete interrupt - refill 2nd half */ + + if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) { + /* fill second half from fifo */ + + if (codec2_fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + /* convert to unsigned */ + + for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) { + sam = (int)(M*(float)signed_buf[i] + C); + dac1_buf[j] = (unsigned short)sam; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5); + } + + GPIOE->ODR &= ~(1 << 1); +} + +/* + This function handles DMA1 Stream 6 interrupt request for DAC2. +*/ + +void DMA1_Stream6_IRQHandler(void) { + int i, j, sam; + short signed_buf[DAC_BUF_SZ/2]; + + GPIOE->ODR |= (1 << 2); + + /* Transfer half empty interrupt - refill first half */ + + if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) { + /* fill first half from fifo */ + + if (codec2_fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + /* convert to unsigned */ + + for(i=0; i<DAC_BUF_SZ/2; i++) { + sam = (int)(M*(float)signed_buf[i] + C); + dac2_buf[i] = (unsigned short)sam; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6); + } + + /* Transfer complete interrupt - refill 2nd half */ + + if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) { + /* fill second half from fifo */ + + if (codec2_fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + /* convert to unsigned */ + + for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) { + sam = (int)(M*(float)signed_buf[i] + C); + dac2_buf[j] = (unsigned short)sam; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); + } + + GPIOE->ODR &= ~(1 << 2); +} diff --git a/stm32/src/stm32f4_machdep.c b/stm32/src/stm32f4_machdep.c new file mode 100644 index 0000000..59f9ed7 --- /dev/null +++ b/stm32/src/stm32f4_machdep.c @@ -0,0 +1,92 @@ + +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_machdep.c + AUTHOR......: David Rowe + DATE CREATED: May 2 2013 + + STM32F4 implementation of the machine dependent timer functions, + e.g. profiling using a clock cycle counter.. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <string.h> +#include "machdep.h" + +#ifdef SEMIHOST_USE_STDIO +#include "stdio.h" +#else +#include "gdb_stdio.h" +#define printf gdb_stdio_printf +#endif + +volatile unsigned int *DWT_CYCCNT = (volatile unsigned int *)0xE0001004; +volatile unsigned int *DWT_CONTROL = (volatile unsigned int *)0xE0001000; +volatile unsigned int *SCB_DEMCR = (volatile unsigned int *)0xE000EDFC; + +#define CORE_CLOCK 168E6 +#define BUF_SZ 4096 + +static char buf[BUF_SZ]; + +void machdep_profile_init(void) +{ + static int enabled = 0; + + if (!enabled) { + *SCB_DEMCR = *SCB_DEMCR | 0x01000000; + *DWT_CYCCNT = 0; // reset the counter + *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter + + enabled = 1; + } + *buf = 0; +} + +void machdep_profile_reset(void) +{ + *DWT_CYCCNT = 0; // reset the counter +} + +unsigned int machdep_profile_sample(void) { + return *DWT_CYCCNT; +} + +/* log to a buffer, we only call printf after timing finished as it is slow */ + +unsigned int machdep_profile_sample_and_log(unsigned int start, char s[]) +{ + char tmp[80]; + float msec; + + unsigned int dwt = *DWT_CYCCNT - start; + msec = 1000.0*(float)dwt/CORE_CLOCK; + snprintf(tmp, sizeof(tmp), "%s %5.2f msecs\n",s,(double)msec); + if ((strlen(buf) + strlen(tmp)) < BUF_SZ) + strncat(buf, tmp, sizeof(buf)-1); + return *DWT_CYCCNT; +} + +void machdep_profile_print_logged_samples(void) +{ + printf("%s", buf); + *buf = 0; +} + diff --git a/stm32/src/stm32f4_usart.c b/stm32/src/stm32f4_usart.c new file mode 100644 index 0000000..4aa0259 --- /dev/null +++ b/stm32/src/stm32f4_usart.c @@ -0,0 +1,71 @@ +/* + stm32f4_usart.c + David Rowe May 2019 + + Basic USART tty support for the stm32. + + From: + http://stm32projectconsulting.blogspot.com/2013/04/stm32f4-discovery-usart-example.html +*/ + +#include <stm32f4xx.h> +#include <stm32f4xx_usart.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include "stm32f4_usart.h" + +#define MAX_FMT_SIZE 256 + +void usart_init(void){ + + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + + /* enable peripheral clock for USART3 */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + + /* GPIOB clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + + /* GPIOA Configuration: USART3 TX on PB10 */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + /* Connect USART3 pins to AF2 */ + // TX = PB10 + GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3); + + USART_InitStructure.USART_BaudRate = 115200; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Tx; + USART_Init(USART3, &USART_InitStructure); + + USART_Cmd(USART3, ENABLE); // enable USART3 + +} + +void usart_puts(const char s[]) { + for (int i=0; i<strlen(s); i++) { + USART_SendData(USART3, s[i]); + while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); + } +} + +int usart_printf(const char *fmt, ...) +{ + char s[MAX_FMT_SIZE]; + va_list ap; + va_start(ap, fmt); + vsnprintf(s, MAX_FMT_SIZE, fmt, ap); + va_end(ap); + usart_puts(s); + return 1; +} diff --git a/stm32/src/stm32f4_usb_vcp.c b/stm32/src/stm32f4_usb_vcp.c new file mode 100644 index 0000000..f30ecfb --- /dev/null +++ b/stm32/src/stm32f4_usb_vcp.c @@ -0,0 +1,90 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_usb_vcp.c + AUTHOR......: xenovacivus + DATE CREATED: 3 Sep 2014 + + USB Virtual COM Port (VCP) module adapted from code I found here: + + https://github.com/xenovacivus/STM32DiscoveryVCP + +\*---------------------------------------------------------------------------*/ + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_exti.h" +#include "usbd_cdc_core.h" +#include "usbd_usr.h" +#include "usbd_desc.h" +#include "usbd_cdc_vcp.h" +#include "usb_dcd_int.h" +#include "sm1000_leds_switches.h" +#include "stm32f4_usb_vcp.h" + +/* + * The USB data must be 4 byte aligned if DMA is enabled. This macro handles + * the alignment, if necessary (it's actually magic, but don't tell anyone). + */ +__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END; + + +/* + * Define prototypes for interrupt handlers here. The conditional "extern" + * ensures the weak declarations from startup_stm32f4xx.c are overridden. + */ +#ifdef __cplusplus + extern "C" { +#endif + +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 OTG_FS_IRQHandler(void); +void OTG_FS_WKUP_IRQHandler(void); + +#ifdef __cplusplus +} +#endif + + +void usb_vcp_init() { + /* Setup USB */ + USBD_Init(&USB_OTG_dev, + USB_OTG_FS_CORE_ID, + &USR_desc, + &USBD_CDC_cb, + &USR_cb); +} + + +/* + * Interrupt Handlers + */ + +void NMI_Handler(void) {} +void SVC_Handler(void) {} +void DebugMon_Handler(void) {} +void PendSV_Handler(void) {} + +void OTG_FS_IRQHandler(void) +{ + USBD_OTG_ISR_Handler (&USB_OTG_dev); +} + +void OTG_FS_WKUP_IRQHandler(void) +{ + if(USB_OTG_dev.cfg.low_power) + { + *(uint32_t *)(0xE000ED10) &= 0xFFFFFFF9 ; + SystemInit(); + USB_OTG_UngateClock(&USB_OTG_dev); + } + EXTI_ClearITPendingBit(EXTI_Line18); +} diff --git a/stm32/src/stm32f4_vrom.c b/stm32/src/stm32f4_vrom.c new file mode 100644 index 0000000..5b66126 --- /dev/null +++ b/stm32/src/stm32f4_vrom.c @@ -0,0 +1,724 @@ +/*! + * STM32F4 Virtual EEPROM driver + * + * This module implements a crude virtual EEPROM device stored in on-board + * flash. The STM32F405 has 4 16kB flash sectors starting at address + * 0x80000000, followed by a 64kB sector, then 128kB sectors. + * + * The Cortex M4 core maps these all to address 0x00000000 when booting + * from normal flash, so the first sector is reserved for interrupt + * vectors. + * + * Everything else however is free game, and so we use these smaller + * sectors to store our configuration. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include "stm32f4_vrom.h" +#include "stm32f4xx_flash.h" +#include "stm32f4xx_crc.h" + +#define VROM_SECT_SZ (16384) /*!< Size of a flash sector */ +#define VROM_SECT_CNT (3) /*!< Number of sectors */ +#define VROM_BLOCK_SZ (256) /*!< Size of a flash block */ + +/*! + * Starting address for the flash area + */ +#define VROM_START_ADDR (0x08004000) + +/*! + * Number of blocks we can fit per sector, including the index block. + */ +#define VROM_BLOCK_CNT (VROM_SECT_SZ / VROM_BLOCK_SZ) + +/*! + * Number of application blocks we can fit per sector. + */ +#define VROM_SECT_APP_BLOCK_CNT (VROM_BLOCK_CNT - 1) + +/*! + * Total number of application blocks we can fit in flash. + */ +#define VROM_APP_BLOCK_CNT (VROM_SECT_CNT * VROM_SECT_APP_BLOCK_CNT) + +/*! + * Maximum number of erase cycles per sector. + * Table 42 (page 109) of STM32F405 datasheet (DocID022152 Rev 5). + */ +#define VROM_MAX_CYCLES (10000) + +/*! + * EEPROM block header. + */ +struct __attribute__ ((__packed__)) vrom_block_hdr_t { + /*! + * CRC32 checksum of the data, offset, size and ROM ID. + * A CRC32 of 0x00000000 indicates an obsoleted block. + * A CRC32 of 0xffffffff indicates an erased block. + */ + uint32_t crc32; + /*! + * ROM ID. + */ + uint8_t rom; + /*! + * Block number in the virtual EEPROM. + */ + uint8_t idx; + /*! + * Number of bytes from the virtual EEPROM stored in this block. + */ + uint8_t size; + /*! + * Reserved for future use. + */ + uint8_t reserved; +}; + +/*! + * The size of a block header in bytes. + */ +#define VROM_BLOCK_HDR_SZ (sizeof(struct vrom_block_hdr_t)) + +/*! + * The amount of data available for application use. + */ +#define VROM_DATA_SZ (VROM_BLOCK_SZ - VROM_BLOCK_HDR_SZ) + +/*! + * EEPROM data block. + */ +struct __attribute__ ((__packed__)) vrom_data_block_t { + /*! Block header */ + struct vrom_block_hdr_t header; + + /*! Block data */ + uint8_t data[VROM_DATA_SZ]; +}; + +/*! + * The first block in a sector is the sector index block. This indicates + * the used/free state of the entire block and counts the number of + * erase cycles for the sector. The index block has no header. + */ +struct __attribute__ ((__packed__)) vrom_sector_idx_t { + /*! + * Number of erase cycles remaining for the sector. + * 0xffffffff == unprogrammed. + */ + uint32_t cycles_remain; + /*! + * Block metadata flags. One for each data block in the sector. + * Does not include the index block. + */ + uint16_t flags[VROM_SECT_APP_BLOCK_CNT]; +}; + +#define VROM_SFLAGS_USED (1 << 0) /*!< Block in use */ + +/*! + * Return the address of a virtual EEPROM sector header. + */ +static const struct vrom_sector_idx_t* vrom_get_sector_hdr(uint8_t sector) +{ + return (const struct vrom_sector_idx_t*)( + VROM_START_ADDR + (VROM_SECT_SZ * sector)); +} + +/*! + * Return the address of a virtual EEPROM block. + */ +static const struct vrom_data_block_t* vrom_get_block( + uint8_t sector, uint8_t block) +{ + return (const struct vrom_data_block_t*)( + (void*)vrom_get_sector_hdr(sector) + + (VROM_BLOCK_SZ * (block + 1))); +} + +/*! + * Compute the CRC32 of a block. + */ +static uint32_t vrom_crc32( + const struct vrom_data_block_t* const block) +{ + struct vrom_data_block_t temp_block; + uint32_t size = sizeof(temp_block); + const uint8_t* in = (const uint8_t*)(&temp_block); + uint32_t tmp; + uint32_t crc; + + memcpy(&temp_block, block, sizeof(temp_block)); + temp_block.header.crc32 = 0; + + CRC_ResetDR(); + while(size) { + tmp = 0; + if (size) { + tmp |= (uint32_t)(*(in++)) << 24; + size--; + } + if (size) { + tmp |= (uint32_t)(*(in++)) << 16; + size--; + } + if (size) { + tmp |= (uint32_t)(*(in++)) << 8; + size--; + } + if (size) { + tmp |= (uint32_t)(*(in++)); + size--; + } + crc = CRC_CalcCRC(tmp); + } + return crc; +} + +/*! + * Find the block storing the given index. + */ +static const struct vrom_data_block_t* vrom_find(uint8_t rom, uint8_t idx) +{ + int sector, block; + + for (sector = 0; sector < VROM_SECT_CNT; sector++) { + const struct vrom_sector_idx_t* sect_hdr + = vrom_get_sector_hdr(sector); + if (sect_hdr->cycles_remain == UINT32_MAX) + /* unformatted */ + continue; + for (block = 0; block < VROM_SECT_APP_BLOCK_CNT; block++) { + const struct vrom_data_block_t* block_ptr; + if (sect_hdr->flags[block] == UINT16_MAX) + /* unformatted */ + continue; + if (sect_hdr->flags[block] == 0) + /* obsolete */ + continue; + + block_ptr = vrom_get_block(sector, block); + + /* Verify the content */ + if (vrom_crc32(block_ptr) + != block_ptr->header.crc32) + /* corrupt */ + continue; + + if (block_ptr->header.rom != rom) + /* different ROM */ + continue; + + if (block_ptr->header.idx != idx) + /* wrong index */ + continue; + + return block_ptr; + } + } + return NULL; +} + +/*! + * Get the sector number of a given address. + */ +static uint8_t vrom_sector_num(const void* address) +{ + /* Get the offset from the base address */ + uint32_t offset = (uint32_t)address - VROM_START_ADDR; + return offset / VROM_SECT_SZ; +} + +/*! + * Get the block number of a given address. + */ +static uint8_t vrom_block_num(const void* address) +{ + /* Get the sector number */ + uint8_t sector = vrom_sector_num(address); + + /* Get the offset from the sector base */ + uint32_t offset = (uint32_t)(address + - (const void*)vrom_get_sector_hdr(sector)); + offset /= VROM_BLOCK_SZ; + return offset - 1; +} + +/*! + * (Erase and) Format a sector. + * + * @retval -EIO Erase failed + * @retval -EPERM Erase counter depleted. + */ +static int vrom_format_sector(const struct vrom_sector_idx_t* sector) +{ + uint8_t sector_num = vrom_sector_num(sector); + uint32_t cycles_remain = VROM_MAX_CYCLES; + if (sector->cycles_remain != UINT32_MAX) { + if (sector->cycles_remain == 0) + /* This sector is exhausted */ + return -EPERM; + + /* This sector has been formatted before */ + cycles_remain = sector->cycles_remain - 1; + if (FLASH_EraseSector(sector_num + 1, VoltageRange_3)) + /* Erase failed */ + return -EIO; + } + + /* Program the new sector cycle counter */ + if (FLASH_ProgramWord((uint32_t)sector, + cycles_remain) == FLASH_COMPLETE) + return 0; /* All good */ + /* If we get here, then programming failed */ + return -EIO; +} + +/*! + * Find the next available block. + */ +static const struct vrom_data_block_t* vrom_find_free(uint8_t run_gc) +{ + int sector; + if (run_gc) { + for (sector = 0; sector < VROM_SECT_CNT; sector++) { + uint8_t block; + uint8_t used = 0; + const struct vrom_sector_idx_t* sect_hdr + = vrom_get_sector_hdr(sector); + if (sect_hdr->cycles_remain == UINT32_MAX) + /* Already erased */ + continue; + if (sect_hdr->cycles_remain == 0) + /* Depleted */ + continue; + + for (block = 0; block < VROM_SECT_APP_BLOCK_CNT; + block++) { + if (sect_hdr->flags[block]) { + used = 1; + break; + } + } + + if (!used) { + /* We can format this */ + vrom_format_sector(sect_hdr); + } + } + } + + for (sector = 0; sector < VROM_SECT_CNT; sector++) { + uint8_t block; + const struct vrom_sector_idx_t* sect_hdr + = vrom_get_sector_hdr(sector); + if (sect_hdr->cycles_remain == UINT32_MAX) { + /* Unformatted sector. */ + if (vrom_format_sector(sect_hdr)) + /* Couldn't format, keep looking */ + continue; + } + for (block = 0; block < VROM_SECT_APP_BLOCK_CNT; block++) { + if (sect_hdr->flags[block] == UINT16_MAX) + /* Success */ + return vrom_get_block(sector, block); + } + } + + /* No blocks free, but have we done garbage collection? */ + if (!run_gc) + return vrom_find_free(1); + + /* If we get here, then we weren't able to find a free block */ + return NULL; +} + +/*! + * Set flags for a block + */ +static int vrom_set_flags(const struct vrom_data_block_t* block, + uint16_t flags) +{ + const struct vrom_sector_idx_t* sector = + vrom_get_sector_hdr(vrom_sector_num(block)); + uint8_t block_num = vrom_block_num(block); + + /* Compute the new flags settings */ + flags = sector->flags[block_num] & ~flags; + + /* Write them */ + if (FLASH_ProgramHalfWord( + (uint32_t)(&(sector->flags[block_num])), + flags) != FLASH_COMPLETE) + return -EIO; + return 0; +} + +/*! + * Mark a block as being obsolete + */ +static int vrom_mark_obsolete(const struct vrom_data_block_t* block) +{ + /* Blank out the CRC */ + if (FLASH_ProgramWord((uint32_t)(&(block->header.crc32)), 0) + != FLASH_COMPLETE) + return -EIO; + /* Blank out the ROM ID */ + if (FLASH_ProgramByte((uint32_t)(&(block->header.rom)), 0) + != FLASH_COMPLETE) + return -EIO; + /* Blank out the index */ + if (FLASH_ProgramByte((uint32_t)(&(block->header.idx)), 0) + != FLASH_COMPLETE) + return -EIO; + /* Blank out the size */ + if (FLASH_ProgramByte((uint32_t)&(block->header.size), 0) + != FLASH_COMPLETE) + return -EIO; + /* Blank out the reserved byte */ + if (FLASH_ProgramByte((uint32_t)&(block->header.reserved), 0) + != FLASH_COMPLETE) + return -EIO; + /* Blank out the flags */ + return vrom_set_flags(block, -1); +} + +/*! + * Write a new block. + */ +static int vrom_write_block(uint8_t rom, uint8_t idx, uint8_t size, + const uint8_t* in) +{ + /* Find a new home for the block */ + const struct vrom_data_block_t* block = vrom_find_free(0); + struct vrom_data_block_t new_block; + uint8_t* out = (uint8_t*)(block); + uint32_t rem = sizeof(new_block); + int res; + + if (!block) + return -ENOSPC; + + /* Prepare the new block */ + memset(&new_block, 0xff, sizeof(new_block)); + new_block.header.rom = rom; + new_block.header.idx = idx; + new_block.header.size = size; + memcpy(new_block.data, in, size); + new_block.header.crc32 = vrom_crc32(&new_block); + + /* Start writing out the block */ + in = (uint8_t*)(&new_block); + rem = VROM_BLOCK_SZ; + while(rem) { + if (*out != *in) { + if (FLASH_ProgramByte((uint32_t)out, *in) + != FLASH_COMPLETE) + /* Failed! */ + return -EIO; + } + in++; + out++; + rem--; + } + res = vrom_set_flags(block, VROM_SFLAGS_USED); + if (res < 0) + return res; + return size; +} + +/*! + * Re-write the given block if needed. + */ +static int vrom_rewrite_block(const struct vrom_data_block_t* block, + uint8_t size, const uint8_t* in) +{ + uint8_t obsolete = 0; + uint8_t rom = block->header.rom; + uint8_t idx = block->header.idx; + const uint8_t* cmp_block = block->data; + const uint8_t* cmp_in = in; + uint8_t cmp_sz = size; + int res; + while(cmp_sz) { + if (*cmp_block != *cmp_in) { + obsolete = 1; + break; + } + cmp_sz--; + cmp_block++; + cmp_in++; + } + + if (!obsolete) + /* The block is fine, leave it be. */ + return size; + + /* Mark the block as obsolete */ + res = vrom_mark_obsolete(block); + if (res) + return res; + return vrom_write_block(rom, idx, size, in); +} + +/*! + * Overwrite the start of a block. + */ +static int vrom_overwrite_block( + const struct vrom_data_block_t* block, + uint8_t offset, uint8_t size, const uint8_t* in) +{ + uint8_t data[VROM_DATA_SZ]; + uint16_t block_sz = block->header.size; + int res; + + if (!offset && (size >= block->header.size)) + /* Complete overwrite */ + return vrom_rewrite_block(block, size, in); + + if (offset) { + /* Overwrite end of block, possible expansion */ + block_sz = offset + size; + if (block_sz > VROM_DATA_SZ) + block_sz = VROM_DATA_SZ; + memcpy(data, block->data, offset); + memcpy(&data[offset], in, block_sz - offset); + } else { + /* Overwrite start of block, no size change */ + memcpy(data, in, size); + memcpy(&data[size], &(block->data[size]), + block_sz - size); + } + + res = vrom_rewrite_block(block, block_sz, data); + if (res < 0) + return res; + return block_sz; +} + +/*! + * Write data to the virtual EEPROM. + */ +static int vrom_write_internal(uint8_t rom, + uint16_t offset, uint16_t size, const uint8_t* in) +{ + /* Figure out our starting block and offset */ + uint8_t block_idx = offset / VROM_DATA_SZ; + uint8_t block_offset = offset % VROM_DATA_SZ; + int count = 0; + + /* Locate the first block */ + const struct vrom_data_block_t* block = vrom_find(rom, block_idx); + + uint8_t block_sz = VROM_DATA_SZ; + if (block_sz > (size + block_offset)) + block_sz = size + block_offset; + + if (!block) { + /* Create a new block */ + uint8_t data[VROM_DATA_SZ]; + int res; + memset(data, 0xff, sizeof(data)); + memcpy(&data[block_offset], in, + block_sz-block_offset); + res = vrom_write_block(rom, block_idx, block_sz, data); + if (res < 0) + return res; + } else { + /* Overwrite block */ + int res = vrom_overwrite_block(block, block_offset, + block_sz, in); + if (res < 0) + return res; + count += block_sz; + } + + block_idx++; + size -= block_sz - block_offset; + + while(size) { + /* Work out how much data to write */ + if (size < VROM_DATA_SZ) + block_sz = size; + else + block_sz = VROM_DATA_SZ; + + int res; + + /* Is there a block covering this range? */ + block = vrom_find(rom, block_idx); + if (block) + res = vrom_overwrite_block( + block, 0, block_sz, in); + else + res = vrom_write_block(rom, block_idx, + block_sz, in); + + if (res < 0) + return res; + + /* Successful write */ + count += res; + size -= res; + in += res; + offset += res; + } + return count; +} + +/*! + * Read data from a virtual EEPROM. + * @param rom ROM ID to start reading. + * @param offset Address offset into ROM to start reading. + * @param size Number of bytes to read from ROM. + * @param out Buffer to write ROM content to. + * @returns Number of bytes read from ROM. + * @retval -ENXIO ROM not found + * @retval -ESPIPE Offset past end of ROM. + */ +int vrom_read(uint8_t rom, uint16_t offset, uint16_t size, void* out) +{ + /* Figure out our starting block and offset */ + uint8_t block_idx = offset / VROM_DATA_SZ; + uint8_t block_offset = offset % VROM_DATA_SZ; + uint8_t block_sz; + int count = 0; + uint8_t* out_ptr = (uint8_t*)out; + + /* Locate the first block */ + const struct vrom_data_block_t* block = vrom_find(rom, block_idx); + + if (!block) + return -ENXIO; + + if (block_offset >= block->header.size) + return -ESPIPE; + + /* Copy the initial bytes */ + block_sz = block->header.size - block_offset; + if (block_sz > size) + block_sz = size; + memcpy(out_ptr, &(block->data[block_offset]), block_sz); + out_ptr += block_sz; + size -= block_sz; + count += block_sz; + + if (size) { + /* Look for the next block */ + block = vrom_find(rom, ++block_idx); + while(size && block) { + if (block->header.size <= size) + block_sz = block->header.size; + else + block_sz = size; + memcpy(out_ptr, block->data, block_sz); + out_ptr += block_sz; + size -= block_sz; + count += block_sz; + + block = vrom_find(rom, ++block_idx); + } + } + + return count; +} + +/*! + * Write data to a virtual EEPROM. + * @param rom ROM ID to start writing. + * @param offset Address offset into ROM to start writing. + * @param size Number of bytes to write to ROM. + * @param in Buffer to write ROM content from. + * @returns Number of bytes written to ROM. + * @retval -EIO Programming failed + * @retval -ENOSPC No free blocks available + */ +int vrom_write(uint8_t rom, uint16_t offset, uint16_t size, + const void* in) +{ + int res; + FLASH_Unlock(); + FLASH_ClearFlag(FLASH_FLAG_EOP + | FLASH_FLAG_OPERR + | FLASH_FLAG_WRPERR + | FLASH_FLAG_PGAERR + | FLASH_FLAG_PGPERR + | FLASH_FLAG_PGSERR); + res = vrom_write_internal(rom, offset, size, in); + FLASH_Lock(); + return res; +} + +/*! + * Erase a virtual EEPROM. + * @param rom ROM ID to erase. + * @returns Number of bytes written to ROM. + * @retval -EIO Programming failed + * @retval -ENOSPC No free blocks available + */ +int vrom_erase(uint8_t rom) +{ + int sector, block; + FLASH_Unlock(); + FLASH_ClearFlag(FLASH_FLAG_EOP + | FLASH_FLAG_OPERR + | FLASH_FLAG_WRPERR + | FLASH_FLAG_PGAERR + | FLASH_FLAG_PGPERR + | FLASH_FLAG_PGSERR); + for (sector = 0; sector < VROM_SECT_CNT; sector++) { + const struct vrom_sector_idx_t* sect_hdr + = vrom_get_sector_hdr(sector); + if (sect_hdr->cycles_remain == UINT32_MAX) + /* unformatted */ + continue; + for (block = 0; block < VROM_SECT_APP_BLOCK_CNT; block++) { + int res; + const struct vrom_data_block_t* block_ptr; + if (sect_hdr->flags[block] == UINT16_MAX) + /* unformatted */ + continue; + if (sect_hdr->flags[block] == 0) + /* obsolete */ + continue; + + block_ptr = vrom_get_block(sector, block); + + /* Verify the content */ + if (vrom_crc32(block_ptr) + != block_ptr->header.crc32) + /* corrupt */ + continue; + + if (block_ptr->header.rom != rom) + /* different ROM */ + continue; + + /* + * Block is valid, for the correct ROM. Mark it + * obsolete. + */ + res = vrom_mark_obsolete(block_ptr); + if (res) + return res; + } + } + return 0; +} diff --git a/stm32/src/system_stm32f4xx.c b/stm32/src/system_stm32f4xx.c new file mode 100644 index 0000000..b8bdd96 --- /dev/null +++ b/stm32/src/system_stm32f4xx.c @@ -0,0 +1,585 @@ +/** + ****************************************************************************** + * @file system_stm32f4xx.c + * @author MCD Application Team + * @version V1.0.1 + * @date 10-July-2012 + * @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.1.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 25MHz, 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 | 352 + *----------------------------------------------------------------------------- + * PLLI2S_R | 2 + *----------------------------------------------------------------------------- + * I2S input clock(Hz) | 176000000 + * | + * To achieve the following I2S config: | + * - Master clock output (MCKO): OFF | + * - Frame wide : 16bit | + * - Error % : 0,0000 | + * - Prescaler Odd factor (ODD): 1 | + * - Linear prescaler (DIV) : 14 | + *----------------------------------------------------------------------------- + * VDD(V) | 3,3 + *----------------------------------------------------------------------------- + * Main regulator output voltage | Scale1 mode + *----------------------------------------------------------------------------- + * 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f4xx_system + * @{ + */ + +/** @addtogroup STM32F4xx_System_Private_Includes + * @{ + */ + +#include "stm32f4xx.h" + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F4xx_System_Private_Defines + * @{ + */ + +/************************* Miscellaneous Configuration ************************/ +/*!< 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 Parameters *************************************/ +/* 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 START_I2SCLOCK 0 +#define PLLI2S_N 352 +#define PLLI2S_R 2 + +/******************************************************************************/ + +/** + * @} + */ + +/** @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) +{ + /* FPU settings ------------------------------------------------------------*/ +#if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ +#endif + /* 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) + { + /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + PWR->CR |= PWR_CR_VOS; + + /* 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) + { + asm("nop"); + } + } + 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 */ + /******************************************************************************/ + +#if START_I2SCLOCK + /* 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) + { + } +#endif +} + +/** + * @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; + FSMC_Bank1E->BWTR[2] = 0x0fffffff; + /* + Bank1_SRAM2 is configured as follow: + + p.FSMC_AddressSetupTime = 3; + p.FSMC_AddressHoldTime = 0; + p.FSMC_DataSetupTime = 6; + 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/stm32/src/tone.c b/stm32/src/tone.c new file mode 100644 index 0000000..ab56792 --- /dev/null +++ b/stm32/src/tone.c @@ -0,0 +1,151 @@ +/*! + * Fixed-point tone generator. + * + * The code here implements a simple fixed-point tone generator that uses + * integer arithmetic to generate a sinusoid at a fixed sample rate of + * 16kHz. + * + * To set the initial state of the state machine, you specify a frequency + * and duration using tone_reset. The corresponding C file embeds a + * sinusoid look-up table. The total number of samples is computed for + * the given time and used to initialise 'remain', 'time' is initialised + * to 0, and 'step' gives the amount to increment 'time' by each iteration. + * + * The samples are retrieved by repeatedly calling tone_next. This + * advances 'time' and decrements 'remain'. The tone is complete when + * 'remain' is zero. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "tone.h" + +/*! Fixed-point shift factor */ +#define TONE_SHIFT (12) + +/*! Static compiled quarter-sinusoid. */ +static const int16_t partial_sine[] = { + 830, 2488, 4140, 5781, 7407, 9014, 10598, 12155, + 13681, 15171, 16623, 18031, 19394, 20707, 21967, 23170, + 24314, 25395, 26411, 27360, 28238, 29043, 29774, 30429, + 31006, 31503, 31919, 32253, 32504, 32672, 32756 +}; + +/*! Length of quarter-sinusoid in samples */ +#define TONE_PART_SINE_LEN (sizeof(partial_sine)\ + /sizeof(partial_sine[0])) + +/*! Total length of sinusoid */ +#define TONE_SINE_LEN ((TONE_PART_SINE_LEN*4)+4) + +/*! + * Generate a sine from the quarter-waveform. + */ +static int16_t tone_sine(uint8_t sample) +{ + /* Key points */ + if ((sample % (TONE_SINE_LEN/2)) == 0) + /* Zero crossings */ + return 0; + if (sample == TONE_SINE_LEN/4) + /* Maximum */ + return INT16_MAX; + if (sample == (3*TONE_SINE_LEN)/4) + /* Minimum */ + return INT16_MIN; + + if (sample < TONE_SINE_LEN/4) + /* First quarter of sine wave */ + return partial_sine[sample-1]; + + if (sample < (TONE_SINE_LEN/2)) + /* Second quarter */ + return partial_sine[(TONE_SINE_LEN/2)-sample-1]; + if (sample < ((3*TONE_SINE_LEN)/4)) + /* Third quarter */ + return -partial_sine[(sample-3) % TONE_PART_SINE_LEN]; + if (sample < TONE_SINE_LEN) + /* Final quarter */ + return -partial_sine[TONE_SINE_LEN-sample-1]; + /* We should not get here */ + return 0; +} + +/*! + * Re-set the tone generator. + * + * @param tone_gen Tone generator to reset. + * @param freq Frequency in Hz, 0 = silence. + * @param duration Duration in milliseconds. 0 to stop. + */ +void tone_reset( + struct tone_gen_t* const tone_gen, + uint16_t freq, uint16_t duration) +{ + if (freq) + /* Compute the time step */ + tone_gen->step = (((2*freq*TONE_SINE_LEN) << TONE_SHIFT) + / ((2*TONE_FS) + 1) + 1); + else + /* DC tone == silence */ + tone_gen->step = 0; + + /* Compute remaining samples */ + tone_gen->remain = (uint16_t)( + ((uint32_t)(TONE_FS * duration)) / 1000); + + /* Initialise the sample counter */ + tone_gen->sample = 0; +} + +/*! + * Retrieve the next sample from the tone generator. + * @param tone_gen Tone generator to update. + */ +int16_t tone_next( + struct tone_gen_t* const tone_gen) +{ + if (!tone_gen) + return 0; + if (!tone_gen->remain) + return 0; + if (!tone_gen->step) { + /* Special case, emit silence */ + tone_gen->remain--; + return 0; + } + + /* Compute sample index */ + uint16_t sample_int = ((tone_gen->sample) >> TONE_SHIFT) + % TONE_SINE_LEN; + + /* Advance tone generator state */ + tone_gen->sample += tone_gen->step; + tone_gen->remain--; + + return tone_sine(sample_int); +} + +/*! + * Retrieve the current time in milliseconds. + */ +uint32_t tone_msec(const struct tone_gen_t* const tone_gen) +{ + uint64_t ms = tone_gen->sample; + ms *= 1000; + ms /= TONE_FS; + return ms >> TONE_SHIFT; +} diff --git a/stm32/src/tot.c b/stm32/src/tot.c new file mode 100644 index 0000000..1fce495 --- /dev/null +++ b/stm32/src/tot.c @@ -0,0 +1,90 @@ +/*! + * Time-out timer. + * + * This is a simple time-out timer for ensuring a maximum transmission + * time is observed. The time-out timer is configured with a total time + * in "ticks", which get counted down in an interrupt. + * + * When the "warning" level is reached, a flag is repeatedly set permit + * triggering of LEDs/sounds to warn the user that time is nearly up. + * + * Upon timeout, a separate flag is set to indicate timeout has taken + * place. + * + * Author Stuart Longland <[email protected]> + * Copyright (C) 2015 FreeDV project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. This program is + * distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "tot.h" + +/*! + * Reset the time-out timer. This zeroes the counter and event flags. + */ +void tot_reset(struct tot_t * const tot) +{ + tot->event = 0; + tot->remaining = 0; + tot->warn_remain = 0; + tot->ticks = 0; +} + +/*! + * Start the time-out timer ticking. + */ +void tot_start(struct tot_t * const tot, uint32_t tot_ticks, + uint16_t warn_ticks) +{ + tot->event = TOT_EVT_START; + tot->warn_remain = tot_ticks - warn_ticks; + tot->remaining = tot_ticks; + tot->ticks = tot->tick_period; +} + +/*! + * Update the time-out timer state. + */ +void tot_update(struct tot_t * const tot) +{ + if (!tot->event) + /* We are not active */ + return; + + if (tot->event & TOT_EVT_DONE) + /* We are done, do not process */ + return; + + if (tot->ticks) + /* Wait for a tick to pass */ + return; + + /* One "tick" has passed */ + if (!tot->remaining) { + /* Time-out reached, reset all flags except timeout */ + tot->event |= TOT_EVT_TIMEOUT | TOT_EVT_DONE; + return; + } else { + tot->remaining--; + } + + if (!tot->warn_remain) { + /* Warning period has passed */ + tot->event |= TOT_EVT_WARN | TOT_EVT_WARN_NEXT; + tot->warn_remain = tot->remain_warn_ticks; + } else { + tot->warn_remain--; + } + + tot->ticks = tot->tick_period; +} diff --git a/stm32/src/usart_ut.c b/stm32/src/usart_ut.c new file mode 100644 index 0000000..b8b229f --- /dev/null +++ b/stm32/src/usart_ut.c @@ -0,0 +1,30 @@ +/* + usart_ut.c + David Rowe May 2019 + + Unit test for stm32 USART support. + + tio is useful to receive the serial strings: + + $ tio -m INLCRNL /dev/ttyUSB0 +*/ + +#include <stm32f4xx.h> +#include "stm32f4_usart.h" + +void Delay(uint32_t nCount) +{ + while(nCount--) + { + } +} + +int main(void){ + + usart_init(); + + while(1){ + usart_puts("Hello, World\n"); + Delay(0x3FFFFF); + } +} diff --git a/stm32/src/usb_vcp_ut.c b/stm32/src/usb_vcp_ut.c new file mode 100644 index 0000000..ff6ebd3 --- /dev/null +++ b/stm32/src/usb_vcp_ut.c @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: usb_vcp_ut.c + AUTHOR......: xenovacivus + DATE CREATED: 31 August 2014 + + USB Virtual COM Port (VCP) unit test that I found here: + + https://github.com/xenovacivus/STM32DiscoveryVCP + + Remarkably, it compiled and ran first time, and even the LEDs blink + as advertised, they just happen to match the LEDs on the SM1000! + However the speed was capped at about 130 kB/s. After a lot of + messing around I found suggestions in the comments from a similar + library here: + + http://stm32f4-discovery.com/2014/08/library-24-virtual-com-port-vcp-stm32f4xx/ + + The key was changing APP_RX_DATA_SIZE in usbd_conf.h to 10000. I + guess the previous size of 2048 was constraining the length of USB + packets, and the USB overhead meant slow throughput. I could + achieve a max of 450 kB/s with this change, about 1/3 of the + theoretical 1.5 MB/s max for USB FS (12 Mbit/s). + + I used this to test grabbing data from the STM32F4 Discovery: + $ sudo dd if=/dev/ttyACM0 of=/dev/null count=100 + 4+96 records in + 44+1 records out + 22615 bytes (23 kB) copied, 0.150884 s, 150 kB/s + + However I occasionally see: + $ sudo dd if=/dev/ttyACM0 of=/dev/null count=100 + dd: failed to open ‘/dev/ttyACM0’: Device or resource busy + + Googling found some suggestion that this is due to "modem manager", however I + removed MM and the problem still exists. + +\*---------------------------------------------------------------------------*/ + +#include <stm32f4xx.h> +#include <stm32f4xx_gpio.h> +#include "stm32f4_usb_vcp.h" +#include "sm1000_leds_switches.h" + +volatile uint32_t ticker, buf_ticker; + +#define N 640*6 + +short buf[N]; + +int main(void) { + int i; + + for(i=0; i<N; i++) + buf[i] = 0; + + sm1000_leds_switches_init(); + usb_vcp_init(); + SysTick_Config(SystemCoreClock/1000); + + while (1) { + + /* Blink the discovery red LED at 1Hz */ + + if (ticker > 500) { + GPIOD->BSRRH = GPIO_Pin_13; + } + if (ticker > 1000) { + ticker = 0; + GPIOD->BSRRL = GPIO_Pin_13; + } + + /* Every 40ms send a buffer, simulates 16 bit samples at Fs=96kHz */ + + if (buf_ticker > 40) { + buf_ticker = 0; + led_pwr(1); + VCP_send_buffer((uint8_t*)buf, sizeof(buf)); + led_pwr(0); + } + + } + + return 0; +} + +/* + * Interrupt Handler + */ + +void SysTick_Handler(void) +{ + ticker++; + buf_ticker++; +} + diff --git a/stm32/src/usb_vsp_ut.c b/stm32/src/usb_vsp_ut.c new file mode 100644 index 0000000..8f0c9f4 --- /dev/null +++ b/stm32/src/usb_vsp_ut.c @@ -0,0 +1,192 @@ + +#define HSE_VALUE ((uint32_t)8000000) /* STM32 discovery uses a 8Mhz external crystal */ + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_exti.h" +#include "usbd_cdc_core.h" +#include "usbd_usr.h" +#include "usbd_desc.h" +#include "usbd_cdc_vcp.h" +#include "usb_dcd_int.h" + +volatile uint32_t ticker, downTicker; + +/* + * The USB data must be 4 byte aligned if DMA is enabled. This macro handles + * the alignment, if necessary (it's actually magic, but don't tell anyone). + */ +__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END; + + +void init(); +void ColorfulRingOfDeath(void); + +/* + * Define prototypes for interrupt handlers here. The conditional "extern" + * ensures the weak declarations from startup_stm32f4xx.c are overridden. + */ +#ifdef __cplusplus + extern "C" { +#endif + +void SysTick_Handler(void); +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 OTG_FS_IRQHandler(void); +void OTG_FS_WKUP_IRQHandler(void); + +#ifdef __cplusplus +} +#endif + + + +int main(void) +{ + /* Set up the system clocks */ + SystemInit(); + + /* Initialize USB, IO, SysTick, and all those other things you do in the morning */ + init(); + + + while (1) + { + /* Blink the orange LED at 1Hz */ + if (500 == ticker) + { + GPIOD->BSRRH = GPIO_Pin_13; + } + else if (1000 == ticker) + { + ticker = 0; + GPIOD->BSRRL = GPIO_Pin_13; + } + + + /* If there's data on the virtual serial port: + * - Echo it back + * - Turn the green LED on for 10ms + */ + uint8_t theByte; + if (VCP_get_char(&theByte)) + { + VCP_put_char(theByte); + + + GPIOD->BSRRL = GPIO_Pin_12; + downTicker = 10; + } + if (0 == downTicker) + { + GPIOD->BSRRH = GPIO_Pin_12; + } + } + + return 0; +} + + +void init() +{ + /* STM32F4 discovery LEDs */ + GPIO_InitTypeDef LED_Config; + + /* Always remember to turn on the peripheral clock... If not, you may be up till 3am debugging... */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + LED_Config.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; + LED_Config.GPIO_Mode = GPIO_Mode_OUT; + LED_Config.GPIO_OType = GPIO_OType_PP; + LED_Config.GPIO_Speed = GPIO_Speed_25MHz; + LED_Config.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOD, &LED_Config); + + + + /* Setup SysTick or CROD! */ + if (SysTick_Config(SystemCoreClock / 1000)) + { + ColorfulRingOfDeath(); + } + + + /* Setup USB */ + USBD_Init(&USB_OTG_dev, + USB_OTG_FS_CORE_ID, + &USR_desc, + &USBD_CDC_cb, + &USR_cb); + + return; +} + +/* + * Call this to indicate a failure. Blinks the STM32F4 discovery LEDs + * in sequence. At 168Mhz, the blinking will be very fast - about 5 Hz. + * Keep that in mind when debugging, knowing the clock speed might help + * with debugging. + */ +void ColorfulRingOfDeath(void) +{ + uint16_t ring = 1; + while (1) + { + uint32_t count = 0; + while (count++ < 500000); + + GPIOD->BSRRH = (ring << 12); + ring = ring << 1; + if (ring >= 1<<4) + { + ring = 1; + } + GPIOD->BSRRL = (ring << 12); + } +} + +/* + * Interrupt Handlers + */ + +void SysTick_Handler(void) +{ + ticker++; + if (downTicker > 0) + { + downTicker--; + } +} + +void NMI_Handler(void) {} +void HardFault_Handler(void) { ColorfulRingOfDeath(); } +void MemManage_Handler(void) { ColorfulRingOfDeath(); } +void BusFault_Handler(void) { ColorfulRingOfDeath(); } +void UsageFault_Handler(void){ ColorfulRingOfDeath(); } +void SVC_Handler(void) {} +void DebugMon_Handler(void) {} +void PendSV_Handler(void) {} + +void OTG_FS_IRQHandler(void) +{ + USBD_OTG_ISR_Handler (&USB_OTG_dev); +} + +void OTG_FS_WKUP_IRQHandler(void) +{ + if(USB_OTG_dev.cfg.low_power) + { + *(uint32_t *)(0xE000ED10) &= 0xFFFFFFF9 ; + SystemInit(); + USB_OTG_UngateClock(&USB_OTG_dev); + } + EXTI_ClearITPendingBit(EXTI_Line18); +} diff --git a/stm32/stlink/elfsym.c b/stm32/stlink/elfsym.c new file mode 100644 index 0000000..b764bf5 --- /dev/null +++ b/stm32/stlink/elfsym.c @@ -0,0 +1,145 @@ +/* + elfsym.c + + Read symbol addresses from a .elf file. + + Based on libelf-howto.c from: http://em386.blogspot.com + + Unit test with: + + gcc elfsym.c -o elfsym -D__UNITTEST__ -Wall -lelf + ./elfsym elf_file.elf +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <libelf.h> +#include <gelf.h> +#include "elfsym.h" + +#define ERR -1 + +int elfsym_open(char file[]) { + int fd; /* File Descriptor */ + char *base_ptr; /* ptr to our object in memory */ + struct stat elf_stats; /* fstat struct */ + + if((fd = open(file, O_RDWR)) == ERR) { + printf("couldn't open %s\n", file); + return ERR; + } + + if((fstat(fd, &elf_stats))) { + printf("could not fstat %s\n", file); + close(fd); + return ERR; + } + + if((base_ptr = (char *) malloc(elf_stats.st_size)) == NULL) { + fprintf(stderr, "could not malloc\n"); + close(fd); + return ERR; + } + + if((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) { + fprintf(stderr, "could not read %s\n", file); + free(base_ptr); + close(fd); + return ERR; + } + + /* Check libelf version first */ + + if(elf_version(EV_CURRENT) == EV_NONE) { + fprintf(stderr, "WARNING Elf Library is out of date!\n"); + } + + free(base_ptr); + + return fd; +} + + +void elfsym_close(int fd) { + close(fd); +} + +unsigned int elfsym_get_symbol_address(int fd, char symbol_name[]) +{ + Elf_Scn *scn; /* Section Descriptor */ + Elf_Data *edata; /* Data Descriptor */ + GElf_Sym sym; /* Symbol */ + GElf_Shdr shdr; /* Section Header */ + Elf *elf; /* Our Elf pointer for libelf */ + unsigned int symbol_address; + int symbol_count; + int i; + + /* Iterate through section headers, stop when we find symbols, + and check for match */ + + elf = elf_begin(fd, ELF_C_READ, NULL); + if (elf == 0) { + fprintf(stderr, "could not elf_begin\n"); + } + symbol_address = 0; + scn = NULL; + + while((scn = elf_nextscn(elf, scn)) != 0) { + gelf_getshdr(scn, &shdr); + + // When we find a section header marked SHT_SYMTAB stop and get symbols + edata = NULL; + if(shdr.sh_type == SHT_SYMTAB) { + // edata points to our symbol table + edata = elf_getdata(scn, edata); + + // how many symbols are there? this number comes from the size of + // the section divided by the entry size + symbol_count = shdr.sh_size / shdr.sh_entsize; + + // loop through to grab all symbols + for(i = 0; i < symbol_count; i++) { + // libelf grabs the symbol data using gelf_getsym() + gelf_getsym(edata, i, &sym); + + if (strcmp(symbol_name, + elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) { + symbol_address = sym.st_value; + } + } + + } + } + + return symbol_address; +} + +#ifdef __UNITTEST__ + +int main(int argc, char *argv[]) +{ + int fd; + unsigned int flag_addr, ptr_addr, file_addr, len_addr; + + fd = elfsym_open(argv[1]); + flag_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_flag"); + ptr_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_ptr"); + file_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_file"); + len_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_len"); + elfsym_close(fd); + + printf("flag_addr: 0x%x\n", flag_addr); + printf("ptr_addr: 0x%x\n", ptr_addr); + printf("file_addr: 0x%x\n", file_addr); + printf("len_addr: 0x%x\n", len_addr); + + return 0; +} + +#endif diff --git a/stm32/stlink/elfsym.h b/stm32/stlink/elfsym.h new file mode 100644 index 0000000..1a3532a --- /dev/null +++ b/stm32/stlink/elfsym.h @@ -0,0 +1,14 @@ +/* + elfsym.h + + Read symbol addresses from a .elf file. +*/ + +#ifndef __ELFSYM__ +#define __ELFSYM__ + +int elfsym_open(char file[]); +void elfsym_close(int fd); +unsigned int elfsym_get_symbol_address(int fd, char symbol_name[]); + +#endif diff --git a/stm32/stlink/stlink.patch b/stm32/stlink/stlink.patch new file mode 100644 index 0000000..6f87450 --- /dev/null +++ b/stm32/stlink/stlink.patch @@ -0,0 +1,428 @@ +diff --git Makefile.am Makefile.am +index a315dd7..7406216 100644 +--- Makefile.am ++++ Makefile.am +@@ -7,7 +7,7 @@ bin_PROGRAMS = st-flash st-util + noinst_LIBRARIES = libstlink.a + + st_flash_SOURCES = flash/main.c +-st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c mingw/mingw.c mingw/mingw.h ++st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c gdbserver/elfsym.c mingw/mingw.c mingw/mingw.h + + CFILES = \ + src/stlink-common.c \ +@@ -24,14 +24,14 @@ HFILES = \ + + libstlink_a_SOURCES = $(CFILES) $(HFILES) + +-libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 ++libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -g + libstlink_a_LIBADD = $(LIBOBJS) + + st_flash_LDADD = libstlink.a +-st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw ++st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw + +-st_util_LDADD = libstlink.a +-st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw ++st_util_LDADD = libstlink.a -lelf ++st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw + + EXTRA_DIST = autogen.sh + +diff --git gdbserver/Makefile gdbserver/Makefile +index bd5c73d..6763388 100644 +--- gdbserver/Makefile ++++ gdbserver/Makefile +@@ -1,12 +1,11 @@ + PRG := st-util +-OBJS = gdb-remote.o gdb-server.o ++OBJS = gdb-remote.o gdb-server.o elfsym.o + + CFLAGS+=-g -Wall -Werror -std=gnu99 -I../src + LDFLAGS=-L.. -lstlink + + # libusb location +-LDFLAGS+=`pkg-config --libs libusb-1.0` +-CFLAGS+=`pkg-config --cflags libusb-1.0` ++LDFLAGS+=`pkg-config --libs libusb-1.0` -lelfCFLAGS+=`pkg-config --cflags libusb-1.0` + + all: $(PRG) + +diff --git gdbserver/gdb-server.c gdbserver/gdb-server.c +index f92fc05..e54d136 100644 +--- gdbserver/gdb-server.c ++++ gdbserver/gdb-server.c +@@ -1,11 +1,12 @@ + /* -*- tab-width:8 -*- */ +-#define DEBUG 0 ++//#define DEBUG 0 + /* + Copyright (C) 2011 Peter Zotov <[email protected]> + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. + */ + ++#include <assert.h> + #include <getopt.h> + #include <stdio.h> + #include <string.h> +@@ -20,14 +21,29 @@ + #include <arpa/inet.h> + #include <signal.h> + #endif ++#include <sys/stat.h> ++#include <unistd.h> ++#include <fcntl.h> + + #include <stlink-common.h> + + #include "gdb-remote.h" ++#include "elfsym.h" + + #define DEFAULT_LOGGING_LEVEL 50 + #define DEFAULT_GDB_LISTEN_PORT 4242 + ++/* stdio command codes from target */ ++ ++#define GDB_STDIO_PRINTF 1 ++#define GDB_STDIO_FOPEN 2 ++#define GDB_STDIO_FCLOSE 3 ++#define GDB_STDIO_FWRITE 4 ++#define GDB_STDIO_FREAD 5 ++#define GDB_STDIO_FPRINTF 6 ++ ++#define MAX_STR 256 ++ + #define STRINGIFY_inner(name) #name + #define STRINGIFY(name) STRINGIFY_inner(name) + +@@ -46,11 +62,12 @@ typedef struct _st_state_t { + // "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTE531X6-if00-port0" is only 58 chars + char devicename[100]; + int logging_level; +- int listen_port; ++ int listen_port; ++ char elf_filename[255]; + } st_state_t; + + +-int serve(stlink_t *sl, int port); ++int serve(stlink_t *sl, int port, char *elf_filename); + char* make_memory_map(stlink_t *sl); + + +@@ -76,13 +93,14 @@ int parse_options(int argc, char** argv, st_state_t *st) { + " -p 4242, --listen_port=1234\n" + "\t\t\tSet the gdb server listen port. " + "(default port: " STRINGIFY(DEFAULT_GDB_LISTEN_PORT) ")\n" ++ " -f <elf_filename>\tenable File I/O of target executable elf_filename" + ; + + + int option_index = 0; + int c; + int q; +- while ((c = getopt_long(argc, argv, "hv::d:s:1p:", long_options, &option_index)) != -1) { ++ while ((c = getopt_long(argc, argv, "hv::d:s:1p:1f:", long_options, &option_index)) != -1) { + switch (c) { + case 0: + printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n"); +@@ -110,25 +128,29 @@ int parse_options(int argc, char** argv, st_state_t *st) { + strcpy(st->devicename, optarg); + } + break; +- case '1': +- st->stlink_version = 1; +- break; +- case 's': +- sscanf(optarg, "%i", &q); +- if (q < 0 || q > 2) { +- fprintf(stderr, "stlink version %d unknown!\n", q); +- exit(EXIT_FAILURE); +- } +- st->stlink_version = q; +- break; +- case 'p': +- sscanf(optarg, "%i", &q); +- if (q < 0) { +- fprintf(stderr, "Can't use a negative port to listen on: %d\n", q); +- exit(EXIT_FAILURE); +- } +- st->listen_port = q; +- break; ++ case '1': ++ st->stlink_version = 1; ++ break; ++ case 's': ++ sscanf(optarg, "%i", &q); ++ if (q < 0 || q > 2) { ++ fprintf(stderr, "stlink version %d unknown!\n", q); ++ exit(EXIT_FAILURE); ++ } ++ st->stlink_version = q; ++ break; ++ case 'p': ++ sscanf(optarg, "%i", &q); ++ if (q < 0) { ++ fprintf(stderr, "Can't use a negative port to listen on: %d\n", q); ++ exit(EXIT_FAILURE); ++ } ++ st->listen_port = q; ++ break; ++ case 'f': ++ sscanf(optarg, "%s", st->elf_filename); ++ printf("-f arg; %s\n", st->elf_filename); ++ break; + } + } + +@@ -162,7 +184,7 @@ int main(int argc, char** argv) { + sl = stlink_v1_open(state.logging_level); + if(sl == NULL) return 1; + break; +- } ++ } + + printf("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id); + +@@ -177,7 +199,7 @@ int main(int argc, char** argv) { + } + #endif + +- while(serve(sl, state.listen_port) == 0); ++ while(serve(sl, state.listen_port, state.elf_filename) == 0); + + #ifdef __MINGW32__ + winsock_error: +@@ -625,7 +647,179 @@ error: + return error; + } + +-int serve(stlink_t *sl, int port) { ++static unsigned int func_addr, ret_addr, pstr1_addr, pstr2_addr; ++static unsigned int strlen1_addr, strlen2_addr, file_addr, ptr_addr; ++static unsigned int size_addr, nmem_addr; ++ ++static void write_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) { ++ /* write the buffer right after the loader */ ++ size_t chunk = size & ~0x3; ++ size_t rem = size & 0x3; ++ ++ if (chunk) { ++ memcpy(sl->q_buf, buf, chunk); ++ stlink_write_mem32(sl, target_addr, chunk); ++ } ++ if (rem) { ++ memcpy(sl->q_buf, buf+chunk, rem); ++ stlink_write_mem8(sl, target_addr+chunk, rem); ++ } ++} ++ ++static void read_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) { ++ unsigned adj_start = target_addr % 4; ++ unsigned count_rnd = (size + adj_start + 4 - 1) / 4 * 4; ++ size_t i; ++ ++ stlink_read_mem32(sl, target_addr - adj_start, count_rnd); ++ ++ for(i=0; i<size; i++) ++ buf[i] = sl->q_buf[i + adj_start]; ++} ++ ++static void fileio(stlink_t *sl) ++{ ++ int func, pstr1, pstr2, strlen1, strlen2, ptr, size, nmem; ++ int ret = 0; ++ FILE *file; ++ char file_name[MAX_STR]; ++ char mode[MAX_STR]; ++ char *buf; ++ ++ stlink_read_mem32(sl, func_addr, 4); ++ func = read_uint32(sl->q_buf, 0); ++ ++ /* func != 0 means target has requested a system call */ ++ ++ switch(func) { ++ ++ case GDB_STDIO_PRINTF: ++ stlink_read_mem32(sl, pstr1_addr, 4); ++ pstr1 = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, strlen1_addr, 4); ++ strlen1 = read_uint32(sl->q_buf, 0); ++ buf = (char*)malloc(strlen1+1); ++ assert(buf != NULL); ++ read_buffer(sl, pstr1, buf, strlen1); ++ buf[strlen1] = 0; ++ #ifdef DEBUG ++ //printf("gdb_stdio printf pstr1: 0x%0x strlen1: %d buf: %s\n", pstr1, strlen1, buf); ++ #endif ++ fputs(buf, stdout); ++ free(buf); ++ ++ break; ++ ++ case GDB_STDIO_FPRINTF: ++ stlink_read_mem32(sl, file_addr, 4); ++ file = (FILE*)read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, pstr1_addr, 4); ++ pstr1 = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, strlen1_addr, 4); ++ strlen1 = read_uint32(sl->q_buf, 0); ++ buf = (char*)malloc(strlen1+1); ++ assert(buf != NULL); ++ read_buffer(sl, pstr1, buf, strlen1); ++ buf[strlen1] = 0; ++ #ifdef DEBUG ++ //printf("gdb_stdio fprintf pstr1: 0x%0x strlen1: %d buf: %s file: 0x%x\n", pstr1, strlen1, buf, (unsigned int)file); ++ #endif ++ fputs(buf, file); ++ free(buf); ++ ++ break; ++ ++ case GDB_STDIO_FOPEN: ++ stlink_read_mem32(sl, pstr1_addr, 4); ++ pstr1 = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, strlen1_addr, 4); ++ strlen1 = read_uint32(sl->q_buf, 0); ++ assert(strlen1 < MAX_STR); ++ read_buffer(sl, pstr1, file_name, strlen1); ++ file_name[strlen1] = 0; ++ ++ stlink_read_mem32(sl, pstr2_addr, 4); ++ pstr2 = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, strlen2_addr, 4); ++ strlen2 = read_uint32(sl->q_buf, 0); ++ assert(strlen2 < MAX_STR); ++ read_buffer(sl, pstr2, mode, strlen2); ++ mode[strlen2] = 0; ++ ++ file = fopen(file_name, mode); ++ ++ ret = (int)file; ++ #ifdef DEBUG ++ printf("gdb_stdio fopen file_name: %s mode: %s file: 0x%x\n", file_name, mode, (unsigned int)file); ++ #endif ++ break; ++ ++ case GDB_STDIO_FCLOSE: ++ stlink_read_mem32(sl, file_addr, 4); ++ file = (FILE*)read_uint32(sl->q_buf, 0); ++ fclose(file); ++ ++ #ifdef DEBUG ++ printf("gdb_stdio fclose file: 0x%x\n", (unsigned int)file); ++ #endif ++ break; ++ ++ case GDB_STDIO_FWRITE: ++ stlink_read_mem32(sl, ptr_addr, 4); ++ ptr = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, size_addr, 4); ++ size = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, nmem_addr, 4); ++ nmem = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, file_addr, 4); ++ file = (FILE*)read_uint32(sl->q_buf, 0); ++ ++ buf = (char*)malloc(size*nmem); ++ assert(buf != NULL); ++ read_buffer(sl, ptr, buf, size*nmem); ++ ret = fwrite(buf, size, nmem, file); ++ free(buf); ++ #ifdef DEBUG ++ printf("gdb_stdio fwrite ptr: 0x%x size: %d nmem: %d file: 0x%x\n", ++ ptr, size, nmem, (unsigned int)file); ++ #endif ++ break; ++ ++ case GDB_STDIO_FREAD: ++ stlink_read_mem32(sl, ptr_addr, 4); ++ ptr = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, size_addr, 4); ++ size = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, nmem_addr, 4); ++ nmem = read_uint32(sl->q_buf, 0); ++ stlink_read_mem32(sl, file_addr, 4); ++ file = (FILE*)read_uint32(sl->q_buf, 0); ++ ++ buf = (char*)malloc(size*nmem); ++ assert(buf != NULL); ++ ret = fread(buf, size, nmem, file); ++ write_buffer(sl, ptr, buf, size*nmem); ++ free(buf); ++ ++ #ifdef DEBUG ++ printf("gdb_stdio fread ptr: 0x%x size: %d nmem: %d file: 0x%x\n", ++ ptr, size, nmem, (unsigned int)file); ++ #endif ++ break; ++ } ++ ++ if (func) { ++ memcpy(sl->q_buf, &ret, sizeof(int)); ++ stlink_write_mem32(sl, ret_addr, 4); ++ ++ func = 0; ++ memcpy(sl->q_buf, &func, sizeof(int)); ++ stlink_write_mem32(sl, func_addr, 4); ++ } ++} ++ ++ ++int serve(stlink_t *sl, int port, char *elf_filename) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0) { + perror("socket"); +@@ -650,7 +844,33 @@ int serve(stlink_t *sl, int port) { + perror("listen"); + return 1; + } +- ++ ++ /* init for file I/O */ ++ ++ func_addr = ret_addr = pstr1_addr = pstr2_addr = strlen1_addr = strlen2_addr = 0; ++ file_addr = ptr_addr = size_addr = nmem_addr = 0; ++ ++ printf("elf_filename: %s----------------------------------\n", elf_filename); ++ if (*elf_filename != 0) { ++ int fd = elfsym_open(elf_filename); ++ if (fd == -1) ++ exit(0); ++ func_addr = elfsym_get_symbol_address(fd, "gdb_stdio_func"); ++ ret_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ret"); ++ pstr1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr1"); ++ pstr2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr2"); ++ strlen1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen1"); ++ strlen2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen2"); ++ file_addr = elfsym_get_symbol_address(fd, "gdb_stdio_file"); ++ ptr_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ptr"); ++ size_addr = elfsym_get_symbol_address(fd, "gdb_stdio_size"); ++ nmem_addr = elfsym_get_symbol_address(fd, "gdb_stdio_nmem"); ++ elfsym_close(fd); ++ #ifdef DEBUG ++ printf("func_addr: 0x%x\n", func_addr); ++ #endif ++ } ++ + start_again: + stlink_force_debug(sl); + stlink_reset(sl); +@@ -924,8 +1144,13 @@ start_again: + if(sl->core_stat == STLINK_CORE_HALTED) { + break; + } ++ ++ /* file I/O if enabled */ ++ ++ if (*elf_filename != 0) ++ fileio(sl); + +- usleep(100000); ++ usleep(10000); + } + + reply = strdup("S05"); // TRAP diff --git a/stm32/stm32_flash.ld b/stm32/stm32_flash.ld new file mode 100644 index 0000000..b3d2362 --- /dev/null +++ b/stm32/stm32_flash.ld @@ -0,0 +1,151 @@ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of 128K RAM on AHB bus*/ + +/* 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 +{ + /* ISR vectors *must* be placed here as they get mapped to address 0 */ + VECTOR (rx) : ORIGIN = 0x08000000, LENGTH = 16K + /* Virtual EEPROM area, we use the remaining 16kB blocks for this. */ + EEPROM (rx) : ORIGIN = 0x08004000, LENGTH = 48K + /* The rest of flash is used for program data */ + FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 960K + /* Backup memory area */ + BKPSRAM (rwx) : ORIGIN = 0x40024000, LENGTH = 4K + /* Memory area */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + /* Core Coupled Memory */ + CCM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K +} + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >VECTOR + + + .eeprom : + { + . = ALIGN(4); + KEEP(*(.eeprom)) /* special section for persistent data */ + . = ORIGIN(EEPROM) + LENGTH(EEPROM) - 1; + BYTE(0xFF) + . = ALIGN(4); + } >EEPROM = 0xff + + .bkpsram : + { + . = ALIGN(4); + KEEP(*(.bkpsram)) + . = ALIGN(4); + } > BKPSRAM + + .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 */ + _exit = .; + } >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 section */ + _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 + + .ccm (NOLOAD) : + { + . = ALIGN(4); + _sccmram = .; + *(.ccm) + . = ALIGN(4); + _eccmram = .; + } >CCM +} diff --git a/stm32/stm32_ram.ld b/stm32/stm32_ram.ld new file mode 100644 index 0000000..2cd9bd9 --- /dev/null +++ b/stm32/stm32_ram.ld @@ -0,0 +1,116 @@ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of 128K RAM on AHB bus*/ + +/* 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 (rwx) : ORIGIN = 0x20000000, LENGTH = 128K + CCM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K +} + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >RAM + + .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 */ + _exit = .; + } >RAM + + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >RAM + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >RAM + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >RAM + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array*)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } >RAM + + /* 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 section */ + _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 +} diff --git a/stm32/unittest/README_unittest.md b/stm32/unittest/README_unittest.md new file mode 100644 index 0000000..edb959b --- /dev/null +++ b/stm32/unittest/README_unittest.md @@ -0,0 +1,259 @@ +# README Codec2 STM32 Unit Test +Don Reid 2018/2019 + +This is the unittest system for the stm32 implementation of +codec2/FreeDV which runs on Linux systems. It requires a STM32F4xx +processor development board connected to/having a ST-LINK, e.g. a +STM32F4 Discovery board. + +## Quickstart + +Requirements: +* python3/numpy +* arm-none-eabi-gdb install and in your path (see codec2/stm32/README.md) +* STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 (see codec2/stm32/README.md) +* build openocd from source and have it in your path (see below) + +Build codec2 for x86 Linux with unittests. This generates several artifacts required for the stm32 tests: + +``` +$ cd ~/codec2 +$ mkdir build_linux && cd build_linux && cmake -DUNITTEST=1 .. && make +``` + +Now build for the stm32, and run the stm32 ctests: +``` +$ cd ~/codec2/stm32 && mkdir build_stm32 && cd build_stm32 +$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/STM32_Toolchain.cmake -DPERIPHLIBDIR=~/Downloads/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 .. +$ make +$ sudo apt install python3-numpy libncurses5 +$ ctest -V +``` + +You should see tests executing (and passing). They are slow to execute +(30 to 180 seconds each), due to the speed of the semihosting system. + +## If a Test fails + +Explore the files in ```codec2/stm32/unittest/test_run/name_of_test``` + +When each test runs, a directory is created, and several log files generated. + +## Running the stm32 Unit Tests + +1. Tests can be run using the ctest utility (part of cmake) + ``` + $ cd ~/codec2/stm32/build_stm32 + $ ctest + ``` + You can pass -V to see more output: + ``` + $ ctest -V + ``` + You can pass -R <pattern> to run test matching <pattern>. Please note, + that some test have dependencies and will have to run other tests before + being executed + ``` + $ ctest -R ofdm + ``` + To list the available ctests: + ``` + $ ctest -N + ``` +1. To run a single test. This test exercises the entire 700D receive side, + and measures CPU load and memory: + ``` + $ cd ~/codec2/stm32/unittest + $ ./scripts/run_stm32_tst tst_ofdm_api_demod 700D_AWGN_codec + ``` + In general: + ``` + $ ./scripts/run_stm32_test <name_of_test> <test_option> + ``` + +1. To run a test set (example): + ``` + $ cd ~/codec2/stm32/unittest + $ ./scripts/run_all_ldpc_tests + ``` + In general: (codec2, ofdm, ldpc): + ``` + $ ./scripts/run_all_<set_name>_tests + ``` + +## When tests fail + +1. If a test fails, explore the files in the ```test_run``` directory for that test. +1. Try building with ALLOC_DEBUG can be helpful with heap issues: + ``` + $ CFLAGS=-DEBUG_ALLOC cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/STM32_Toolchain.cmake \ + -DPERIPHLIBDIR=~/Downloads/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 .. + ``` + +## Sequence of a Test + +Consider the example: +``` +build_stm32$ ctest -R tst_ldpc_dec_noise +``` + +1. The test is kicked off based on `src/CMakeLists.txt`, which calls `scipts/run_stm32_tst` +1. `run_stm32_tst` calls the test setup script, e.g. `tst_ldpc_dec_setup`. Typically, this will run a host version to generate a reference. +1. `run_stm32_tst` runs the stm32 executable on the Discovery, e.g. `tst_ldpc_dec`, the source is in `src/tst_ldpc_dec.c` +1. The steup and check scripts can handle many sub cases, e.g. `ideal` and `noise`. +1. `run_stm32_tst` calls the test check script, e.g. `tst_ldpc_dec_check` which typically compares the host generated reference to the output from the stm32. +1. As the test runs, various files are generated in `test_run/tst_ldpc_dec_noise` +1. When debugging it's useful to run the ctest with the verbose option: + ``` + $ ctest -V -R tst_ldpc_dec_noise + ``` + Set the `-x` at the top of the scripts to trace execution: + ``` + #!/bin/bash -x + # + # tst_ldpc_enc_check + + ``` + +## Directory Structure + + | Path | Description | + | --- | --- | + | `scripts` | Scripts for unittest system + | `src` | stm32 C sources + | `\src\CMakeLists.txt` | ctests are defined here + | `lib/python`| Python library files + | `lib/octave`| Octave library files + | `test_run` | Files created by each test as it runs + + +## Running the tests remotely + +If the stm32 hardware is connected on a different pc with linux, the tests can be run remotely. +Test will run slower, roughly 3 times. + +1. You have to build OpenOCD on the remote machine with the STM32 board. It must be built from + (https://github.com/db4ple/openocd.git). +1. You don't need OpenOCD installed on your build pc. +1. You have to be able to run ssh with public key authentication using ssh-agent so that + you can ssh into the remote machine without entering a password. +1. You have to call ctest with the proper UT_SSH_PARAMS settings, e.g. +``` +UT_SSH_PARAMS="-p 22 -q remoteuser@remotemachine" ctest -V +``` + +## Debug and Semihosting + +These tests required a connection from the arm-none-eabi-gdb debugger +to the stm32 hardware. For this we use a recent version of +OpenOCD. Running tests with the stm32 hardware connected to a remote +machine via ssh is possible. This works only with a patched (fixed) +OpenOCD, see below. + +## OpenOCD + +We recommend OpenOCD instead of stlink. + +Most linux distributions use old packages for openocd, so you should +build it from the git source. If your test runs fail with error +messages regarding SYS_FLEN not support (see openocd_stderr.log in the +test_run directories), your openocd is too old. Make sure to have the +right openocd first in the PATH if you have multiple openocd +installed! + +It is strongly recommended to build OpenOCD from sources, see below. + +## Building OpenOCD + +OpenOCD needs to be built from the source. + +If you want to use openocd remotely via SSH, you have to use currently the patched +source from (https://github.com/db4ple/openocd.git) instead of the official repository. + +1. + The executable is placed in /usr/local/bin ! Make sure to have no + other openocd installed (check output of `which openocd` to be + /usr/local/bin) + + ```Bash + sudo apt install libusb-1.0-0-dev libtool pkg-config autoconf automake texinfo + git clone https://git.code.sf.net/p/openocd/code openocd-code + cd openocd-code + ./bootstrap + ./configure + sudo make install + which openocd + + sudo cp contrib/60-openocd.rules /etc/udev/rules.d/ + sudo udevadm control --reload-rules + {un plug/plug-in stm32 Discovery} + ``` + +2. Plug in a stm32 development board and test: + +``` + $ openocd -f board/stm32f4discovery.cfg + + Open On-Chip Debugger 0.10.0+dev-00796-ga4ac5615 (2019-04-12-21:58) + Licensed under GNU GPL v2 + For bug reports, read + http://openocd.org/doc/doxygen/bugs.html + Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD + adapter speed: 2000 kHz + adapter_nsrst_delay: 100 + none separate + srst_only separate srst_nogate srst_open_drain connect_deassert_srst + Info : Listening on port 6666 for tcl connections + Info : Listening on port 4444 for telnet connections + Info : clock speed 2000 kHz + Info : STLINK V2J33S0 (API v2) VID:PID 0483:3748 + Info : Target voltage: 2.871855 + Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints + Info : Listening on port 3333 for gdb connections +``` + +## st-util (deprecated) + +Most distributions don't have stutil included. Easiest way is to build it from +the github sources. + +The source can be downloaded from: + + (https://github.com/texane/stlink) + +After compiling it can be installed anywhere, as long as it is in the PATH. The program is in +`build/Release/src/gdbserver/st-util`. + +The newlib stdio functions (open, fread, fwrite, flush, fclose, etc.) send +some requests that this tool does not recognize and those messages will appear +in the output of st-util. They can be ignored. + +1. Build from github + +```Bash + git clone https://github.com/texane/stlink + cd stlink + make + sudo cp ./etc/udev/rules.d/49-stlinkv2.rules /etc/udev/rules.d/ + sudo udevadm control --reload-rules +``` +3. Add the st-util util to your $PATH, if not installed in the default location ( /usr/local/bin ) + +4. Plug in a stm32 development board and test: + +``` + $ st-util + + st-util 1.4.0-47-gae717b9 + 2018-12-29T06:52:16 INFO usb.c: -- exit_dfu_mode + 2018-12-29T06:52:16 INFO common.c: Loading device parameters.... + 2018-12-29T06:52:16 INFO common.c: Device connected is: F4 device, id 0x10016413 + 2018-12-29T06:52:16 INFO common.c: SRAM size: 0x30000 bytes (192 KiB), Flash: 0x100000 bytes (1024 KiB) in pages of 16384 bytes + 2018-12-29T06:52:16 INFO gdb-server.c: Chip ID is 00000413, Core ID is 2ba01477.G + 2018-12-29T06:52:16 INFO gdb-server.c: Listening at *:4242... +``` + + + + +# vi:set ts=3 et sts=3: diff --git a/stm32/unittest/lib/octave/ofdm_demod_check.m b/stm32/unittest/lib/octave/ofdm_demod_check.m new file mode 100644 index 0000000..dd85053 --- /dev/null +++ b/stm32/unittest/lib/octave/ofdm_demod_check.m @@ -0,0 +1,62 @@ +% ofdm_demod_check.m +% +% Load results from reference and stm32 run and compare + +addpath("../../lib/octave") + +% Constants (would prefer parameters) +err_limit = 0.001; + +% Reference +load("ofdm_demod_ref_log.txt"); + +% DUT +load("ofdm_demod_log.txt"); + +% Eliminate trailing rows of all zeros (unused) +sums_ref = sum(payload_syms_log_c, 2); +last_ref = find(sums_ref, 1, 'last'); +sums_dut = sum(payload_syms_log_stm32, 2); +last_dut = find(sums_dut, 1, 'last'); +last_all = max(last_ref, last_dut); + +syms_ref = payload_syms_log_c(1:last_all,:); +syms_dut = payload_syms_log_stm32(1:last_all,:); + +% error values +err = abs(syms_ref - syms_dut); +err_max = max(max(err)); +printf("MAX_ERR %f\n", err_max); + +err_vals = err - err_limit; +err_vals(err_vals<0) = 0; +errors = err_vals > 0; +num_errors = nnz(errors); + +%% TODO, print errors info (count locations,...) +if (num_errors > 0) + printf("%d ERRORS\n", num_errors); +else + printf("PASSED\n"); +end + +% EVM +evm = sqrt(meansq(err, 2)); +evm_avg = mean(evm); +printf("AVG_EVM %f\n", evm_avg); +evm_max = max(evm); +printf("MAX_EVM %f\n", evm_max); + +% Standard deviation +sdv = std(err, 0, 2); +sdv_max = max(sdv); +printf("MAX_SDV %f\n", sdv_max); + +% Plot +figure(1) +figure(1, "visible", true) +scatter(real(syms_ref), imag(syms_ref), "g", "+") +hold on +scatter(real(syms_dut), imag(syms_dut), "b", "o") +print(1, "syms_plot.png", "-dpng") +hold off diff --git a/stm32/unittest/lib/python/sum_profiles.py b/stm32/unittest/lib/python/sum_profiles.py new file mode 100755 index 0000000..19eea13 --- /dev/null +++ b/stm32/unittest/lib/python/sum_profiles.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +""" sum_profiles """ + +def sum_profiles(fin, frames): + data = {} + total_time = 0.0 + active = False + + for line in fin: + if (not active): active = line.startswith("Start Profile Data") + elif line.startswith("End Profile Data"): active = False + else: + words = line.strip().split() + if (len(words) == 3): + part = words[0] + time_str = words[1] + time = float(time_str) + total_time += time + if (not part in data): data[part] = 0.0 + data[part] += time + # end else + # end for line + + data_sorted = [(p, data[p]) for p in sorted(data, key=data.get, reverse=True)] + + print("Total time = {:.1f} ms".format(total_time)) + if (frames): + print("{:.1f} ms per frame".format(total_time / frames)) + print("") + + for part, time in data_sorted: + percent = int(100*(time / total_time)) + print('{:2d}% - {:10.3f} - {}'.format(percent, time, part)) + + return(data) + # end sum_profiles() + + +######################################## +if __name__ == "__main__": + import argparse + + #### Options + argparser = argparse.ArgumentParser() + argparser.add_argument("-f", "--frames", action="store", type=int, default=0, + help="Number of frames") + argparser.add_argument("file", metavar="FILE", help="file to read") + args = argparser.parse_args() + + fin = open(args.file, "r") + sum_profiles(fin, args.frames) diff --git a/stm32/unittest/lib/ut_travis.enc b/stm32/unittest/lib/ut_travis.enc Binary files differnew file mode 100644 index 0000000..e950ac0 --- /dev/null +++ b/stm32/unittest/lib/ut_travis.enc diff --git a/stm32/unittest/scripts/check_ram_limit b/stm32/unittest/scripts/check_ram_limit new file mode 100755 index 0000000..874f46f --- /dev/null +++ b/stm32/unittest/scripts/check_ram_limit @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Compare the amount of RAM used in all stm32 programs to a +# threshold. The idea is trap changes to x86 code that will +# cause out of memory issues on the stm32 +# +# This can be run from the command line or via a ctest, it doesn't +# require stm32 hardware. +# +# usage: +# cd ~/codec2/stm32/build_stm32 +# ./check_ram_limit [threshold] + +echo "Checking end of used RAM in all stm32 programs......." +thresh=0x20006000 +[[ $# -gt 0 ]] && thresh=$1 +map_files=`find . -name '*.map'` +for f in $map_files +do + ram_used=`cat $f | grep bss_end | sed 's/^.*\(0x[a-f0-9]*\).*/\1/'` + printf "%-40s 0x%x\n" $f $ram_used + [[ $ram_used -gt $thresh ]] && echo -e "\n ***** FAIL - LIMIT is $thresh !!! *****\n" && exit 1 +done +echo "PASS" +exit 0 diff --git a/stm32/unittest/scripts/kill_run_stm32_tst b/stm32/unittest/scripts/kill_run_stm32_tst new file mode 100755 index 0000000..ddccd90 --- /dev/null +++ b/stm32/unittest/scripts/kill_run_stm32_tst @@ -0,0 +1,15 @@ +#!/bin/bash + +list_descendants () +{ + local children=$(ps -o pid= --ppid "$1") + + for pid in $children + do + list_descendants "$pid" + done + + echo $children +} + +kill $(list_descendants $(pidof -x run_stm32_tst)) diff --git a/stm32/unittest/scripts/plot_ofdm_demod_syms b/stm32/unittest/scripts/plot_ofdm_demod_syms new file mode 100755 index 0000000..28eb063 --- /dev/null +++ b/stm32/unittest/scripts/plot_ofdm_demod_syms @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" plot_ofdm_demod_syms + + Plot QPSK constelations of reference demods. + + Later read stm32 log...... + + """ + +import numpy as np +import os +import sys + + +############################################################################## +# Read Octave text file +############################################################################## + +def read_octave_text(fname): + data = {} + with open(fname, "r") as f: + for line in f: + if (line[0:8] == '# name: '): + var = line.split()[2] + print('found {}'.format(var)) + line = next(f) + if (line.startswith('# type: matrix')): + line = next(f) + rows = int(line.split()[2]) + line = next(f) + cols = int(line.split()[2]) + print(' matrix({}, {})'.format(rows, cols)) + data[var] = np.empty((rows, cols), np.float32) + # Read rows one at a time + for row in range(rows): + line = next(f) + data[var][row] = np.fromstring(line, np.float32, cols, ' ') + + # end while True + # end with + return(data) + + +############################################################################## +# Main +############################################################################## + +### Text not supported!!! ref_data = sio.loadmat('ofdm_demod_ref_log.mat') + +ref_data = read_octave_text('ofdm_demod_ref_log.txt') + +import pprint +pp = pprint.PrettyPrinter(indent=4) +pp.pprint(ref_data) diff --git a/stm32/unittest/scripts/run_all_codec2_tests b/stm32/unittest/scripts/run_all_codec2_tests new file mode 100755 index 0000000..91cf068 --- /dev/null +++ b/stm32/unittest/scripts/run_all_codec2_tests @@ -0,0 +1,27 @@ +#!/bin/bash +# +# run_all_codec2_tests + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +declare -i Fails=0 + +run_stm32_tst tst_codec2_enc 1300 "$@" || Fails+=1 +run_stm32_tst tst_codec2_enc 700C "$@" || Fails+=1 + +run_stm32_tst tst_codec2_dec 1300 "$@" || Fails+=1 +run_stm32_tst tst_codec2_dec 700C "$@" || Fails+=1 + +if (( $Fails == 0 )); then + echo -e "\nAll Codec2 Tests PASSED" +else + echo -e "\n$Fails Codec2 Tests FAILED!" +fi + +exit $Fails + +# vi:set ts=4 et sts=4: diff --git a/stm32/unittest/scripts/run_all_ldpc_tests b/stm32/unittest/scripts/run_all_ldpc_tests new file mode 100755 index 0000000..98d06a2 --- /dev/null +++ b/stm32/unittest/scripts/run_all_ldpc_tests @@ -0,0 +1,26 @@ +#!/bin/bash +# +# run_all_ldpc_tests + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +declare -i Fails=0 + +run_stm32_tst tst_ldpc_enc "$@" || Fails+=1 + +run_stm32_tst tst_ldpc_dec ideal "$@" || Fails+=1 +run_stm32_tst tst_ldpc_dec noise "$@" || Fails+=1 + +if (( $Fails == 0 )); then + echo -e "\nAll LDPC Tests PASSED" +else + echo -e "\n$Fails LDPC Tests FAILED!" +fi + +exit $Fails + +# vi:set ts=4 et sts=4: diff --git a/stm32/unittest/scripts/run_all_ofdm_tests b/stm32/unittest/scripts/run_all_ofdm_tests new file mode 100755 index 0000000..3f63558 --- /dev/null +++ b/stm32/unittest/scripts/run_all_ofdm_tests @@ -0,0 +1,32 @@ +#!/bin/bash +# +# run_all_ofdm_tests + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +declare -i Fails=0 + +run_stm32_tst tst_ofdm_mod plain "$@" || Fails+=1 +run_stm32_tst tst_ofdm_mod ldpc "$@" || Fails+=1 + +run_stm32_tst tst_ofdm_demod quick "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod ideal "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod AWGN "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod fade "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod ldpc "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod ldpc_AWGN "$@" || Fails+=1 +run_stm32_tst tst_ofdm_demod ldpc_fade "$@" || Fails+=1 + +if (( $Fails == 0 )); then + echo -e "\nAll ODFM Tests PASSED" +else + echo -e "\n$Fails ODFM Tests FAILED!" +fi + +exit $Fails + +# vi:set ts=4 et sts=4: diff --git a/stm32/unittest/scripts/run_all_stm32_tests b/stm32/unittest/scripts/run_all_stm32_tests new file mode 100755 index 0000000..6e066be --- /dev/null +++ b/stm32/unittest/scripts/run_all_stm32_tests @@ -0,0 +1,25 @@ +#!/bin/bash +# +# run_all_codec2_tests + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +declare -i Fails=0 + +run_all_codec2_tests "$@" || Fails+=1 +run_all_ofdm_tests "$@" || Fails+=1 +run_all_ldpc_tests "$@" || Fails+=1 + +if (( $Fails == 0 )); then + echo -e "\nAll STM32 Tests PASSED" +else + echo -e "\n$Fails STM32 Tests FAILED!" +fi + +exit $Fails + +# vi:set ts=4 et sts=4: diff --git a/stm32/unittest/scripts/run_stm32_prog b/stm32/unittest/scripts/run_stm32_prog new file mode 100755 index 0000000..652f715 --- /dev/null +++ b/stm32/unittest/scripts/run_stm32_prog @@ -0,0 +1,91 @@ +#!/bin/bash + +####################################### +# Parse command line options +# Options (starting with "--") are stored in $ARGS. +# Non-options are taken as the test name (last one sticks). + +declare -A ARGS +for arg in "$@"; do + if [[ ${arg} == --* ]] ; then ARGS[${arg}]=true + else ELF=${arg} + fi + done + +# Add the parameters for connecting via ssh to +# your machine with an stm32 connected to +# UT_SSH_PARAMS +# e.g. +# UT_SSH_PARAMS="-p 22 user@host_with_stm32" + +if [ -z "$UT_SSH_PARAMS" ]; then + UT_SSH="" + UT_SLEEP=${UT_SLEEP:=1} + UI_SH_FIO="disable" +else + UT_SSH="ssh -f -L 3333:localhost:3333 $UT_SSH_PARAMS" + UT_SLEEP=${UT_SLEEP:=4} + UT_SH_FIO="enable" +fi + +rm -f gdb_cmds + +if [ ! ${ARGS[--st-util]+_} ] ; then + # OpenOCD + if [ -n "$UT_SSH" ]; then + cat <<-EEOOFF >> gdb_cmds + shell ${UT_SSH} killall -q openocd\; sleep 1\; openocd -d0 -f board/stm32f4discovery.cfg 2> >(tee stderr.log >&2) | tee stdout.log & + EEOOFF + else + cat <<-EEOOFF >> gdb_cmds + shell killall -q openocd + shell openocd -d0 -f board/stm32f4discovery.cfg 2> >(tee stderr.log >&2) | tee stdout.log & + EEOOFF + fi + + cat <<-EEOOFF >> gdb_cmds + shell sleep ${UT_SLEEP} + target remote :3333 + monitor arm semihosting enable + monitor arm semihosting_fileio $UT_SH_FIO + EEOOFF + + SHUTDOWN="monitor shutdown" +else + # ST-Util + echo "---------------------- STARTING gdb/st-util ------------------------------" + cat <<-EEOOFF >> gdb_cmds + shell st-util --verbose=0 --semihosting 2>stutil_stderr.log >stutil_stdout.log & + shell sleep ${UT_SLEEP} + target remote :4242 + EEOOFF + + SHUTDOWN="" +fi + +if [ ! ${ARGS[--noload]+_} ] ; then + cat <<-EEOOFF >> gdb_cmds + load + EEOOFF + fi + +cat <<-EEOOFF >> gdb_cmds + monitor reset halt + monitor adapter speed 4000 + break EndofMain + break abort + EEOOFF + +if [ -z ${ARGS[--debug]+_} ] ; then + cat <<-EEOOFF >> gdb_cmds + shell printf "\n----------------------------STARTING PROGRAM-------------------------\n\n" + continue + set confirm off + $SHUTDOWN + quit + EEOOFF + arm-none-eabi-gdb -batch -x gdb_cmds ${ELF} + else + arm-none-eabi-gdb -x gdb_cmds ${ELF} + fi + diff --git a/stm32/unittest/scripts/run_stm32_tst b/stm32/unittest/scripts/run_stm32_tst new file mode 100755 index 0000000..9cfeef0 --- /dev/null +++ b/stm32/unittest/scripts/run_stm32_tst @@ -0,0 +1,53 @@ +#!/bin/bash +# +# run_stm32_tst <test> <test_sub_type> [--noload] [--st-util] + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +declare -i Fails=0 + +##################################################################### +LOAD=${ARGS[--noload]:+--noload} +STUTIL=${ARGS[--st-util]:+--st-util} +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" +echo -e "test full name: ${FULL_TEST_NAME}" +setup_common "${RUN_DIR}" + +if [ ! -f "${SCRIPTS}/${TEST}_setup" ]; then + echo -e "\nERROR: scripts/${TEST}_setup not found!" + echo "Test name correct?" + echo "valid test names:" + cd scripts; ls tst*setup | sed 's/_setup//' + exit 1 +fi + +# Call setup - run - check scripts +${TEST}_setup ${TEST} ${TEST_OPT} --clean || { echo "ERROR in ${TEST}_setup! Exiting..."; exit 1; } +cd "${RUN_DIR}" +run_stm32_prog ${UNITTEST_BIN}/${TEST}.elf ${LOAD} ${OPENOCD} | tee gdb.log +[ ! ${PIPESTATUS[0]} -eq 0 ] && { echo "ERROR in run_stm32_prog! Exiting..."; exit 1; } +# stop now if we see an assert() fire, no point running check phase +grep -q assertion gdb.log && exit 1 +${TEST}_check ${TEST} ${TEST_OPT} 2>&1 | tee check.log +if [ ! "${PIPESTATUS[0]}" -eq 0 ]; then + let Fails=($Fails + 1) +fi + +sleep 5 # Delay for st-util to close + +if (( $Fails == 0 )); then + echo -e "\nTest ${FULL_TEST_NAME} PASSED" +else + echo -e "\nTest ${FULL_TEST_NAME} FAILED!" + cat ${RUN_DIR}/check.log + echo -e "\n -> look at log files in: ${RUN_DIR}:" + ls ${RUN_DIR} +fi + +exit $Fails + +# vi:set ts=4 et sts=4: diff --git a/stm32/unittest/scripts/run_tests_common.sh b/stm32/unittest/scripts/run_tests_common.sh new file mode 100644 index 0000000..2f950c4 --- /dev/null +++ b/stm32/unittest/scripts/run_tests_common.sh @@ -0,0 +1,79 @@ +# This file must be "sourced" from a parent shell! +# +# run_tests_common.sh +# +# This is a collection of common variable settings for stm32 unit tests. +# +# The variable $SCRIPTS must be set when this is called. + +if [ -z ${SCRIPTS+x} ]; then + echo "Error, run_tests_common.sh requires that \$SCRIPTS be set!" + exit 1 + fi + +####################################### +# Set default directories based on the parent of the SCRIPTS variable. +set -a + +#UNITTEST_BASE - Location of STM32 Unittests and files +UNITTEST_BASE="$( cd "$( dirname "${SCRIPTS}" )" >/dev/null && pwd )" + +# STM32_BASE - Base directory of Stm32 files +STM32_BASE="$( cd "$( dirname "${UNITTEST_BASE}" )" >/dev/null && pwd )" + +# STM32_BUILD - Build directory of Stm32 files +STM32_BUILD="${STM32_BASE}/build_stm32" + +# UNITTEST_BIN - Location of STM32 unittest binaries +UNITTEST_BIN="${STM32_BUILD}/unittest/src" + +# CODEC2_BASE - Base directory of Codec2 +CODEC2_BASE="$( cd "$( dirname "${STM32_BASE}" )" >/dev/null && pwd )" + +# CODEC2_BIN - Location of x86 utiliy programs for Codec2 +CODEC2_BIN="${CODEC2_BASE}/build_linux/src" + +# CODEC2_UTST - Location of x86 utiliy programs for Codec2 unittest +CODEC2_UTST="${CODEC2_BASE}/build_linux/unittest" + +set +a + +####################################### +# Add directories to PATH +export PATH=${PATH}:${SCRIPTS}:${CODEC2_BIN}:${CODEC2_UTST} + + +####################################### +# Parse command line options +# Options (starting with "--") are stored in $ARGS. +# Non-options are taken as the test name, then as a test option (optional) +declare -A ARGS +unset TEST +unset TEST_OPT +for arg in "$@"; do + if [[ ${arg} == --* ]] ; then ARGS[${arg}]=true + else + if [ -z ${TEST+x} ]; then TEST=${arg} + else TEST_OPT=${arg} + fi + fi + done + +# Prepend the common test name to the option if given +if [ -n "$TEST_OPT" ] ; then FULL_TEST_NAME="${TEST}_${TEST_OPT}" +else FULL_TEST_NAME="${TEST}" +fi + +####################################### +# A function for setup + +setup_common () { + + if [ ${ARGS[--clean]+_} ] ; then + if [ -d "${1}" ] ; then rm -rf "${1}"; fi + fi + + # Make run directory if needed + if [ ! -d "${1}" ] ; then mkdir -p "${1}"; fi + + } diff --git a/stm32/unittest/scripts/setup.sh b/stm32/unittest/scripts/setup.sh new file mode 100644 index 0000000..c64906a --- /dev/null +++ b/stm32/unittest/scripts/setup.sh @@ -0,0 +1,19 @@ +# This file must be "sourced" from a parent shell! +# +# setup.sh +# +# This is a collection of common variable settings for manually running +# stm32 unit tests. +# +# This assumes it is called from the "stm32/unittests" directory!!! + +SCRIPTS="${PWD}/scripts" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +####################################### +# Add directories to PATH(s) +export PATH=${SCRIPTS}:${PATH} +export PATH=${CODEC2_BIN}:${CODEC2_UTST}:${CODEC2_UTST_BIN}:${CODEC2_SCRIPT}:${PATH} +export LD_LIBRARY_PATH=${CODEC2_BIN}:${LD_LIBRARY_PATH} diff --git a/stm32/unittest/scripts/stm_stderr.txt b/stm32/unittest/scripts/stm_stderr.txt new file mode 100644 index 0000000..6ff50c5 --- /dev/null +++ b/stm32/unittest/scripts/stm_stderr.txt @@ -0,0 +1,2 @@ +semihosting test - stderr +Error 2 opening fin diff --git a/stm32/unittest/scripts/stm_stdout.txt b/stm32/unittest/scripts/stm_stdout.txt new file mode 100644 index 0000000..2fc0905 --- /dev/null +++ b/stm32/unittest/scripts/stm_stdout.txt @@ -0,0 +1 @@ +semihosting test - stdout diff --git a/stm32/unittest/scripts/sum_profiles b/stm32/unittest/scripts/sum_profiles new file mode 100644 index 0000000..706b8a2 --- /dev/null +++ b/stm32/unittest/scripts/sum_profiles @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +""" sum_profiles """ + +def sum_profiles(fin, frames): + data = {} + total_time = 0.0 + + for line in fin: + words = line.strip().split() + if (len(words) == 3): + part = words[0] + time_str = words[1] + time = float(time_str) + total_time += time + if (not part in data): data[part] = 0.0 + data[part] += time + + data_sorted = [(p, data[p]) for p in sorted(data, key=data.get, reverse=True)] + + print("Total time = {:.1f} ms".format(total_time)) + if (frames): + print("{:.1f} per frame".format(total_time / args.frames)) + print("") + + for part, time in data_sorted: + percent = int(100*(time / total_time)) + print('{:2d}% - {:10.3f} - {}'.format(percent, time, part)) + + return(data) + # end sum_profiles() + + +######################################## +if __name__ == "__main__": + import argparse + + #### Options + argparser = argparse.ArgumentParser() + argparser.add_argument("-f", "--frames", action="store", type=int, default=0, + help="Number of frames") + argparser.add_argument("file", metavar="FILE", help="file to read") + args = argparser.parse_args() + + fin = open(args.file, "r") + sum_profiles(fin, args.frames) diff --git a/stm32/unittest/scripts/tst_api_demod_check b/stm32/unittest/scripts/tst_api_demod_check new file mode 100755 index 0000000..fa6dd03 --- /dev/null +++ b/stm32/unittest/scripts/tst_api_demod_check @@ -0,0 +1,214 @@ +#!/bin/bash +# +# tst_api_demod_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + +# way of performing a rough comparison of two output speech files that are not exactly the same + +function compare_energy() { + energy_ref=$(python3 -c "import numpy as np; x=np.fromfile(\"ref_demod.raw\",dtype=\"int16\").astype(float); print(10*np.log10(np.dot(x,x)))") + energy_target=$(python3 -c "import numpy as np; x=np.fromfile(\"stm_out.raw\",dtype=\"int16\").astype(float); print(10*np.log10(np.dot(x,x)))") + printf "ref energy: %f target energy: %f\n" $energy_ref $energy_target + + python3 -c "import sys; sys.exit(1) if abs($energy_ref-$energy_target) < 1 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "energy compare OK"; + else echo "energy compare BAD"; + let Fails=($Fails + 1) + fi +} + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +case "${TEST_OPT}" in + + 700D_plain_test) + echo "Check reference decode" + p1=$(grep '^BER\.*: 0.000' ref_gen.log | wc -l) + p2=$(grep '^Coded BER: 0.000' ref_gen.log | wc -l) + if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + # + echo "Check target decode" + p1=$(grep '^BER\.*: 0.000' stderr.log | wc -l) + p2=$(grep '^Coded BER: 0.000' stderr.log | wc -l) + if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + ;; + + 700D_AWGN_test) + echo "Check reference decode" + uber_ref=$(cat ref_gen.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p") + cber_ref=$(cat ref_gen.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p") + printf "REF uncoded BER: %f coded BER: %f\n" $uber_ref $cber_ref + + # As per notes in tst_api_demod_setup, coded BER is unreliable + # for such a short test, so we'll just sanity check the + # reference uncoded BER here. Bash can't compare floats + # .... so use return code of some python script + python3 -c "import sys; sys.exit(1) if $uber_ref < 0.1 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + + echo "Check target decode" + uber_target=$(cat stderr.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p") + cber_target=$(cat stderr.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p") + printf "TARGET uncoded BER: %f coded BER: %f\n" $uber_target $cber_target + python3 -c "import sys; sys.exit(1) if $uber_target < 0.1 and abs($cber_ref-$cber_target) < 0.01 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + ;; + + 700D_AWGN_codec) + # 1/ The two output files sound OK, and when plotted look very + # similar, but they don't match on a sample-sample basis. + + # 2/ Suspect some small state difference, or perhaps random + # number generator diverging, sampling codec2_rand() at the + # end of the x86 and stm32 test programs might show up any + # differences. + + # 3/ At this stage - we can't make sample by sample automatic + # tests work. However there is value in running the test + # to ensure no asserts are hit and the code doesn't crash + # (e.g. due to an out of memory issues). A simple energy + # comparison is used on the output speech files, which + # will trap any large errors. + + # 4/ We can also manually evaluate the output decoded speech by + # listening to the output speech files. + + compare_energy; + + # make sure execution time stays within bounds + execution_time=mktmp + cat stdout.log | sed -n "s/.*freedv_rx \([0-9..]*\) msecs/\1/p" > $execution_time + python3 -c "import sys; import numpy as np; x=np.loadtxt(\"$execution_time\"); print(\"execution time max:: %5.2f mean: %5.2f ms\" % (np.max(x), np.mean(x))); sys.exit(1) if np.max(x) < 80.0 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "execution time OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + + ;; + + 700E_plain_test) + echo "Check reference decode" + p1=$(grep '^BER\.*: 0.000' ref_gen.log | wc -l) + p2=$(grep '^Coded BER: 0.000' ref_gen.log | wc -l) + if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + # + echo "Check target decode" + p1=$(grep '^BER\.*: 0.000' stderr.log | wc -l) + p2=$(grep '^Coded BER: 0.000' stderr.log | wc -l) + if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + ;; + + 700E_AWGN_test) + echo "Check reference decode" + uber_ref=$(cat ref_gen.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p") + cber_ref=$(cat ref_gen.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p") + printf "REF uncoded BER: %f coded BER: %f\n" $uber_ref $cber_ref + + # As per notes in tst_api_demod_setup, coded BER is unreliable + # for such a short test, so we'll just sanity check the + # reference uncoded BER here. Bash can't compare floats + # .... so use return code of some python script + python3 -c "import sys; sys.exit(1) if $uber_ref < 0.1 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + + echo "Check target decode" + uber_target=$(cat stderr.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p") + cber_target=$(cat stderr.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p") + printf "TARGET uncoded BER: %f coded BER: %f\n" $uber_target $cber_target + python3 -c "import sys; sys.exit(1) if $uber_target < 0.1 and abs($cber_ref-$cber_target) < 0.01 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + ;; + + 700E_AWGN_codec) + # 1/ The two output files sound OK, and when plotted look very + # similar, but they don't match on a sample-sample basis. + + # 2/ Suspect some small state difference, or perhaps random + # number generator diverging, sampling codec2_rand() at the + # end of the x86 and stm32 test programs might show up any + # differences. + + # 3/ At this stage - we can't make sample by sample automatic + # tests work. However there is value in running the test + # to ensure no asserts are hit and the code doesn't crash + # (e.g. due to an out of memory issues). A simple energy + # comparison is used on the output speech files, which + # will trap any large errors. + + # 4/ We can also manually evaluate the output decoded speech by + # listening to the output speech files. + + compare_energy; + + # make sure execution time stays within bounds + execution_time=mktmp + cat stdout.log | sed -n "s/.*freedv_rx \([0-9..]*\) msecs/\1/p" > $execution_time + python3 -c "import sys; import numpy as np; x=np.loadtxt(\"$execution_time\"); print(\"execution time max:: %5.2f mean: %5.2f ms\" % (np.max(x), np.mean(x))); sys.exit(1) if np.max(x) < 80.0 else sys.exit(0)" + if [[ $? -eq 1 ]]; then echo "execution time OK"; + else echo "BAD"; + let Fails=($Fails + 1) + fi + + ;; + + 1600_plain_codec) + compare_energy; + ;; + + *) + printf "ERROR: invalid test option. Valid options are:\n 700D_plain_test\n 700D_AWGN_test\n 700D_plain_codec\n 1600_plain_codec\n" + exit 1 + + esac + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + + +exit $Fails diff --git a/stm32/unittest/scripts/tst_api_demod_setup b/stm32/unittest/scripts/tst_api_demod_setup new file mode 100755 index 0000000..79d33ed --- /dev/null +++ b/stm32/unittest/scripts/tst_api_demod_setup @@ -0,0 +1,151 @@ +#!/bin/bash +# +# tst_api_demod_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + 700D_plain_test ) + # Config is <mode>, <teswtframes> + echo "71000010" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=100 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700D spch_in.raw stm_in.raw --testframes --txbpf 0 \ + >> setup.log 2>&1 + # + # Reference + freedv_rx 700D stm_in.raw ref_demod.raw -v --testframes \ + > ref_gen.log 2>&1 + ;; + + 700D_AWGN_test ) + # Config is <mode>, <teswtframes> + echo "71000010" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=96 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700D spch_in.raw mod_bits.raw --testframes --txbpf 0 \ + >> setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log + + # Reference: - When the OFDM modem initially syncs, it often + # has residual freq offset that causes abnormally + # high LDPC decoder bit errors forthe first few + # seconds. This leads to a high coded BER being + # reported for short duration tests. This + # settles down after a few seconds, and we get + # the expected coded BER when averaging over + # longer periods (e.g. 60s). However this + # particular test is necessarily short due to the + # slow speed of the semihosting system. It is + # therefore sufficient to check that the + # performance is similar to the x86 C version, + # rather than expecting a low coded BER for a + # short run. + + freedv_rx 700D stm_in.raw ref_demod.raw -v --testframes 2>&1 --discard | tee ref_gen.log + ;; + + 700D_AWGN_codec ) + # Config is <mode>, <teswtframes> + echo "70000020" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700D spch_in.raw mod_bits.raw --txbpf 0 \ + >> setup.log 2>&1 + # + # Reference - give it a hard time with some noise to exercise the LDPC codec and get us to max CPU + ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log + freedv_rx 700D stm_in.raw ref_demod.raw -v \ + > ref_gen.log 2>&1 + ;; + + 700E_plain_test ) + # Config is <mode>, <teswtframes> + echo "81000010" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=100 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700E spch_in.raw stm_in.raw --testframes --txbpf 1 \ + >> setup.log 2>&1 + # + # Reference + freedv_rx 700E stm_in.raw ref_demod.raw -v --testframes \ + > ref_gen.log 2>&1 + ;; + + 700E_AWGN_test ) + # Config is <mode>, <teswtframes> + echo "81000010" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=96 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700E spch_in.raw mod_bits.raw --testframes --txbpf 1 \ + >> setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -22 -f -5 2>&1 | tee setup.log + + freedv_rx 700E stm_in.raw ref_demod.raw -v --testframes 2>&1 --discard | tee ref_gen.log + ;; + + 700E_AWGN_codec ) + # Config is <mode>, <teswtframes> + echo "80000020" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + freedv_tx 700E spch_in.raw mod_bits.raw --txbpf 1 \ + >> setup.log 2>&1 + # + # Reference - give it a hard time with some noise to exercise the LDPC codec and get us to max CPU + ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log + freedv_rx 700E stm_in.raw ref_demod.raw -v \ + > ref_gen.log 2>&1 + ;; + + 1600_plain_codec ) + # Config is <mode>, <teswtframes> + echo "00000010" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=320 count=100 if=../../../../raw/hts1.raw of=spch_in.raw > setup.log 2>&1 + freedv_tx 1600 spch_in.raw stm_in.raw >> setup.log 2>&1 + # + # Reference + freedv_rx 1600 stm_in.raw ref_demod.raw -v \ + > ref_gen.log 2>&1 + ;; + + *) + printf "ERROR: invalid test option. Valid options are:\n 700[DE]_plain_test\n 700[DE]_AWGN_test\n 700[DE]_AWGN_codec\n 1600_plain_codec\n" + exit 1 + ;; + + esac diff --git a/stm32/unittest/scripts/tst_api_mod_check b/stm32/unittest/scripts/tst_api_mod_check new file mode 100755 index 0000000..060d230 --- /dev/null +++ b/stm32/unittest/scripts/tst_api_mod_check @@ -0,0 +1,115 @@ +#!/bin/bash +# +# tst_api_mod_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +case "${TEST_OPT}" in + + 700D_TEST) + # + echo -e "\nReference check" + if freedv_rx 700D ref_mod.raw ref_rx.raw --testframes; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + # + echo -e "\nTarget check" + if freedv_rx 700D stm_out.raw stm_rx.raw --testframes; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + # + echo -e "\nCompare output binary data" + if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + + 700D_CODEC) + # + echo -e "\nCompare output binary data" + if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + + 700E_TEST) + # + echo -e "\nReference check" + if freedv_rx 700E ref_mod.raw ref_rx.raw --testframes; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + # + echo -e "\nTarget check" + if freedv_rx 700E stm_out.raw stm_rx.raw --testframes; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + # + echo -e "\nCompare output binary data" + if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + + 700E_CODEC) + # + echo -e "\nCompare output binary data" + if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + + esac + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + + +exit $Fails diff --git a/stm32/unittest/scripts/tst_api_mod_setup b/stm32/unittest/scripts/tst_api_mod_setup new file mode 100755 index 0000000..a69b9e9 --- /dev/null +++ b/stm32/unittest/scripts/tst_api_mod_setup @@ -0,0 +1,86 @@ +#!/bin/bash +# +# tst_api_mod_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + 700D_TEST ) + # Config is <mode>, <teswtframes>, <clip>, <bpf> + echo "71000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + freedv_tx 700D stm_in.raw ref_mod.raw --testframes --txbpf 0 \ + > ref_gen.log 2>&1 + ;; + + 700D_CODEC ) + # Config is <mode>, <teswtframes>, <clip>, <bpf> + echo "70000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + freedv_tx 700D stm_in.raw ref_mod.raw --txbpf 0 \ + > ref_gen.log 2>&1 + ;; + + 700E_TEST ) + # Config is <mode>, <teswtframes>, <clip>, <bpf> + echo "81110000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + freedv_tx 700E stm_in.raw ref_mod.raw --testframes --txbpf 1 --clip 1 \ + > ref_gen.log 2>&1 + ;; + + 700E_CODEC ) + # Config is <mode>, <teswtframes>, <cip>, <bpf> + echo "80110000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + freedv_tx 700E stm_in.raw ref_mod.raw --txbpf 1 --clip 1 \ + > ref_gen.log 2>&1 + ;; + + *) + printf "ERROR: invalid test option. Valid options are:\n 700D_TEST\n 700D_CODEC\n 700E_TEST\n 700E_CODEC\n" + exit 1 + ;; + esac + +exit 0 diff --git a/stm32/unittest/scripts/tst_codec2_dec_check b/stm32/unittest/scripts/tst_codec2_dec_check new file mode 100755 index 0000000..adb6a90 --- /dev/null +++ b/stm32/unittest/scripts/tst_codec2_dec_check @@ -0,0 +1,43 @@ +#!/bin/bash +# +# tst_codec2_dec_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +#case "${TEST_OPT}" in +# 1300) +# 700C) +# esac + +echo -e "\nMust manually listen to this!" +aplay -f S16_LE stm_out.raw + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + + +exit $Fails diff --git a/stm32/unittest/scripts/tst_codec2_dec_setup b/stm32/unittest/scripts/tst_codec2_dec_setup new file mode 100755 index 0000000..0f38a73 --- /dev/null +++ b/stm32/unittest/scripts/tst_codec2_dec_setup @@ -0,0 +1,54 @@ +#!/bin/bash +# +# tst_codec2_dec_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + 1300 ) + # Config is <mode>, <teswtframes> + echo "41000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + c2enc 1300 spch_in.raw stm_in.raw >> setup.log 2>&1 + # + # Reference + c2dec 1300 stm_in.raw ref_dec.raw > ref_gen.log 2>&1 + ;; + + 700C ) + # Config is <mode>, <teswtframes> + echo "81000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw \ + > setup.log 2>&1 + c2enc 700C spch_in.raw stm_in.raw >> setup.log 2>&1 + # + # Reference + c2dec 700C stm_in.raw ref_dec.raw > ref_gen.log 2>&1 + ;; + + esac diff --git a/stm32/unittest/scripts/tst_codec2_enc_check b/stm32/unittest/scripts/tst_codec2_enc_check new file mode 100755 index 0000000..d95bd18 --- /dev/null +++ b/stm32/unittest/scripts/tst_codec2_enc_check @@ -0,0 +1,59 @@ +#!/bin/bash +# +# tst_codec2_enc_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +case "${TEST_OPT}" in + 1300) + echo -e "\nCompare output binary data" + compare_ints -b1 -c ref_enc.raw stm_out.raw + error_count=$? + if [[ $error_count -le 2 ]]; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + 700C) + echo -e "\nCompare output binary data" + if compare_ints -b1 ref_enc.raw stm_out.raw; then + echo "Passed" + else + echo "Failed" + let Fails=($Fails + 1) + fi + ;; + esac + + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + + +exit $Fails diff --git a/stm32/unittest/scripts/tst_codec2_enc_setup b/stm32/unittest/scripts/tst_codec2_enc_setup new file mode 100755 index 0000000..12fe4eb --- /dev/null +++ b/stm32/unittest/scripts/tst_codec2_enc_setup @@ -0,0 +1,54 @@ +#!/bin/bash +# +# tst_codec2_enc_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + 1300 ) + # Config is <mode>, <teswtframes> + echo "40000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + c2enc 1300 stm_in.raw ref_enc.raw \ + > ref_gen.log 2>&1 + ;; + + 700C ) + # Config is <mode>, <teswtframes> + echo "80000000" > stm_cfg.txt + # + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw \ + > setup.log 2>&1 + # + # Reference + c2enc 700C stm_in.raw ref_enc.raw \ + > ref_gen.log 2>&1 + ;; + + esac diff --git a/stm32/unittest/scripts/tst_ldpc_dec_check b/stm32/unittest/scripts/tst_ldpc_dec_check new file mode 100755 index 0000000..a301798 --- /dev/null +++ b/stm32/unittest/scripts/tst_ldpc_dec_check @@ -0,0 +1,71 @@ +#!/bin/bash +# +# tst_ldpc_enc_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +case "${TEST_OPT}" in + + ideal) + BER_LIMIT_RAW=0.0 + BER_LIMIT_CODED=0.0 + ;; + noise) + BER_LIMIT_RAW=0.15 + BER_LIMIT_CODED=0.015 + ;; + esac + +echo -e "\nCompare output binary data" +if compare_ints -b1 ref_out.raw stm_out.raw; then + echo "Passed" +else + echo "Failed" + let Fails=($Fails + 1) +fi +# + +echo -e "\nReference BER values" +n=$(grep 'Raw.*BER:' ref_gen.log | awk '{print $7}') +p1=$(echo $n '<=' ${BER_LIMIT_RAW} | bc) +n=$(grep 'Coded.*BER:' ref_gen.log | awk '{print $7}') +p2=$(echo $n '<=' ${BER_LIMIT_CODED} | bc) +if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "Pass"; +else echo "Fail"; let Fails=($Fails + 1); fi +# +echo -e "\nTarget BER values" +n=$(grep 'Raw.*BER:' stderr.log | cut -d ' ' -f 7) +p1=$(echo $n '<=' ${BER_LIMIT_RAW} | bc) +n=$(grep 'Coded.*BER:' stderr.log | cut -d ' ' -f 7) +p2=$(echo $n '<=' ${BER_LIMIT_CODED} | bc) +if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "Pass"; +else echo "Fail"; let Fails=($Fails + 1); fi + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + +exit $Fails diff --git a/stm32/unittest/scripts/tst_ldpc_dec_setup b/stm32/unittest/scripts/tst_ldpc_dec_setup new file mode 100755 index 0000000..5370f55 --- /dev/null +++ b/stm32/unittest/scripts/tst_ldpc_dec_setup @@ -0,0 +1,50 @@ +#!/bin/bash +# +# tst_ldpc_dec_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + ideal ) +# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile> +# echo "00000000" > stm_cfg.txt + ldpc_enc /dev/zero stm_in.raw --sd --code HRA_112_112 --testframes 6 \ + > setup.log 2>&1 + ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes \ + > ref_gen.log 2>&1 + ;; + + noise ) +# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile> +# echo "00000000" > stm_cfg.txt + ldpc_enc /dev/zero enc_out.raw --sd --code HRA_112_112 --testframes 24 \ + > setup.log 2>&1 + ldpc_noise enc_out.raw stm_in.raw 1 \ + >> setup.log 2>&1 + ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes \ + > ref_gen.log 2>&1 + ;; + + esac + +exit 0 diff --git a/stm32/unittest/scripts/tst_ldpc_enc_check b/stm32/unittest/scripts/tst_ldpc_enc_check new file mode 100755 index 0000000..69f3f3b --- /dev/null +++ b/stm32/unittest/scripts/tst_ldpc_enc_check @@ -0,0 +1,68 @@ +#!/bin/bash +# +# tst_ldpc_enc_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +#case "${TEST_OPT}" in +# +# plain) +# ;; +# esac + +##### TODO: ldpc_dec should be able to check this outputs, +##### it currently reports Tbits = 0! + +#echo -e "\nReference check" +#if ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --testframes ${LDPC}; then +# echo "Passed" +#else +# echo "Failed" +# let Fails=($Fails + 1) +#fi +## +#echo -e "\nTarget check" +#if ofdm_demod mod.raw stm_demod.raw --testframes ${LDPC}; then +# echo "Passed" +#else +# echo "Failed" +# let Fails=($Fails + 1) +#fi +## +echo -e "\nCompare output binary data" +if compare_ints -b1 ref_out.raw stm_out.raw; then + echo "Passed" +else + echo "Failed" + let Fails=($Fails + 1) +fi +# + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + +exit $Fails diff --git a/stm32/unittest/scripts/tst_ldpc_enc_setup b/stm32/unittest/scripts/tst_ldpc_enc_setup new file mode 100755 index 0000000..1b23ca7 --- /dev/null +++ b/stm32/unittest/scripts/tst_ldpc_enc_setup @@ -0,0 +1,39 @@ +#!/bin/bash +# +# tst_ldpc_enc_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +#case "${TEST_OPT}" in +# +# plain ) +# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile> +# echo "00000000" > stm_cfg.txt + ofdm_get_test_bits --out stm_in.raw --frames 6 --verbose \ + > setup.log 2>&1 + ldpc_enc stm_in.raw ref_out.raw --code HRA_112_112 \ + > ref_gen.log 2>&1 +# ;; +# +# esac + +exit 0 diff --git a/stm32/unittest/scripts/tst_ofdm_demod_check b/stm32/unittest/scripts/tst_ofdm_demod_check new file mode 100755 index 0000000..06e471c --- /dev/null +++ b/stm32/unittest/scripts/tst_ofdm_demod_check @@ -0,0 +1,503 @@ +#!/usr/bin/env python3 +""" tst_ofdm_demod_check + + Testing for tst_ofdm_demod_* tests + + Usage tst_ofdm_demod_check <dummy_test_name> quick|ideal|AWGN|fade|profile|ldpc|ldpc_AWGN|ldpc_fade + + Checks are different for each option, but similar + + - Convert stm32 output to octave text format + (stm32 does not have memory for this) + + - ... + + """ + +import numpy as np +import math +import argparse +import struct +import os +import sys + +if ("UNITTEST_BASE" in os.environ): + sys.path.append(os.environ["UNITTEST_BASE"] + "/lib/python") +else: + sys.path.append("../../lib/python") # assume in test run dir + +import sum_profiles + +Nbitsperframe = 238 + +############################################################################## +# Read Octave text file +############################################################################## + +def read_octave_text(f): + if (args.verbose): print('read_octave_text()') + data = {} + for line in f: + if (line[0:8] == "# name: "): + var = line.split()[2] + if (args.verbose): print(' var "{}"'.format(var)) + line = next(f) + if (line.startswith("# type: matrix")): + line = next(f) + rows = int(line.split()[2]) + line = next(f) + cols = int(line.split()[2]) + if (cols > 0): + data[var] = np.empty((rows, cols), np.float32) + # Read rows one at a time + for row in range(rows): + try: + line = next(f) + data[var][row] = np.fromstring(line, np.float32, cols, " ") + except: + print("Error reading row {} of var {}".format(row, var)) + raise + + elif (line.startswith("# type: complex matrix")): + line = next(f) + rows = int(line.split()[2]) + line = next(f) + cols = int(line.split()[2]) + if (cols > 0): + data[var] = np.empty((rows, cols), np.complex64) + # Read rows one at a time + for row in range(rows): + try: + line = next(f) + # " (r,i) (r,i) ..." + col = 0 + for tpl in line.split(): + real, imag = tpl.strip("(,)").split(",") + data[var][row][col] = float(real) + (1j * float(imag)) + col += 1 + except: + print("Error reading row {} of var {}".format(row, var)) + raise + # end for line in f + return(data) + + +############################################################################## +# Read stm32 diag data, syms, amps for each frame +############################################################################## + +def read_tgt_syms(f): + # TODO: don't use hardcoded values... + syms = np.zeros((100, 112), np.complex64) + amps = np.zeros((100, 112), np.float32) + row = 0 + while True: + # syms + buf = f.read(112 * 8) + if (len(buf) < (112 * 8)): break + row_lst = struct.unpack("<224f", buf) + ary = np.array(row_lst, np.float32) + ary.dtype = np.complex64 + syms[row] = ary + # amps + buf = f.read(112 * 4) + if (len(buf) < (112 * 4)): break + row_lst = struct.unpack("<112f", buf) + ary = np.array(row_lst, np.float32) + amps[row] = ary + # + row += 1 + if (row >= 100): break + # end While True + return(syms, amps) + # end read_stm_syms() + + +############################################################################## +# Write out in octave text format as 2 matricies +############################################################################## + +def write_syms_as_octave(syms, amps): + with open("ofdm_demod_log.txt", "w") as f: + # syms + rows = syms.shape[0] + cols = syms.shape[1] + f.write("# name: payload_syms_log_stm32\n") + f.write("# type: complex matrix\n") + f.write("# rows: {}\n".format(rows)) + f.write("# columns: {}\n".format(cols)) + for row in range(rows): + for col in range(cols): + f.write(" ({},{})".format( + syms[row][col].real, + syms[row][col].imag + )) + f.write("\n") + # amps + rows = amps.shape[0] + cols = amps.shape[1] + f.write("\n") + f.write("# name: payload_amps_log_stm32\n") + f.write("# type: matrix\n") + f.write("# rows: {}\n".format(rows)) + f.write("# columns: {}\n".format(cols)) + for row in range(rows): + for col in range(cols): + f.write(" {}".format( + amps[row][col] + )) + f.write("\n") + # end write_syms_as_octave() + + +############################################################################## +# Main +############################################################################## + +#### Options +argparser = argparse.ArgumentParser() +argparser.add_argument("-v", "--verbose", action="store_true") +argparser.add_argument("test", action="store") +argparser.add_argument("test_opt", action="store", + choices=["quick", "ideal", "AWGN", "fade", "profile", + "ldpc", "ldpc_AWGN", "ldpc_fade" ]) +args = argparser.parse_args() + +# Use ENV value of UNITTEST_BASE from upper level shell script (default to .) +if ('UNITTEST_BASE' in os.environ): + run_dir = os.environ['UNITTEST_BASE'] + "/test_run/" + run_dir += args.test + "_" + args.test_opt + print(run_dir) + os.chdir(run_dir) + +#### Settings +# Defaults, (for tests without channel degradation, results should be close to ideal) +max_ber = 0.001 # Max BER value in Target +max_ber2 = 0.001 # Max Coded BER value in Target +compare_ber = 1 # Compare Target to Reference? +# Used if compare_ber: +tolerance_ber = 0.001 # Difference from reference for BER +tolerance_ber2 = 0.001 # Difference from reference for Coded BER +tolerance_tbits = 0 +tolerance_terrs = 1 +# +compare_output = 1 # Compare Target to Reference? +# Used if compare_output: +tolerance_output_differences = 0 +tolerance_syms = 0.01 +tolerance_amps = 0.01 +# +# Per test settings +if (args.test_opt == "quick"): + pass +elif (args.test_opt == "ideal"): + pass +elif (args.test_opt == "AWGN"): # Still close enough to compare BERs loosely + max_ber = 0.1 + max_ber2 = 0.1 + tolerance_ber = 0.01 + tolerance_ber2 = 0.005 + tolerance_tbits = 1000 + tolerance_terrs = 50 + tolerance_output_differences = 2 + compare_output = 0 +elif (args.test_opt == "fade"): + max_ber = 0.1 + max_ber2 = 0.1 + tolerance_ber = 0.01 + tolerance_ber2 = 0.005 + tolerance_tbits = 1000 + tolerance_terrs = 200 + tolerance_output_differences = 5 + compare_output = 0 + pass +elif (args.test_opt == "profile"): + tolerance_output_differences = 1 + pass +elif (args.test_opt == "ldpc"): + pass +elif (args.test_opt == "ldpc_AWGN"): + max_ber = 0.1 + max_ber2 = 0.01 + compare_ber = 0 + compare_output = 0 +elif (args.test_opt == "ldpc_fade"): + max_ber = 0.1 + max_ber2 = 0.01 + compare_ber = 0 + compare_output = 0 + pass +else: + print("Error: Test {} not recognized".format(args.test_opt)) + sys.exit(1) + +#### Check that we are in the test directory: +#### TODO::: + + +#### Read test configuration - a file of '0' or '1' characters +with open("stm_cfg.txt", "r") as f: + config = f.read(8) + config_verbose = (config[0] == '1') + config_testframes = (config[1] == '1') + config_ldpc_en = (config[2] == '1') + config_log_payload_syms = (config[3] == '1') + config_profile = (config[4] == '1') + + +#### +fails = 0 + + +if (config_testframes): + #### BER checks - log output looks like this, for non-ldpc: + # BER......: 0.1951 Tbits: 14994 Terrs: 2926 + # BER2.....: 0.2001 Tbits: 10234 Terrs: 2048 + # + # Or this, for ldpc: + # BER......: 0.0000 Tbits: 15008 Terrs: 0 + # Coded BER: 0.0000 Tbits: 7504 Terrs: 0 + # + # HACK: store "Coded BER" info as BER2. + + print("\nBER checks") + + # Read ref log + print("Reference") + with open("ref_gen_log.txt", "r") as f: + for line in f: + if (line[0:4] == "BER2"): + print(line, end="") + _, ref_ber2, _, ref_tbits2, _, ref_terrs2 = line.split() + elif (line[0:3] == "BER"): + print(line, end="") + _, ref_ber, _, ref_tbits, _, ref_terrs, _, ref_tpackets, _, ref_snr3k = line.split() + elif (line[0:9] == "Coded BER"): + print(line, end="") + _, _, ref_ber2, _, ref_tbits2, _, ref_terrs2 = line.split() + + # Strings to integers + ref_ber = float(ref_ber) + ref_tbits = int(ref_tbits) + ref_terrs = int(ref_terrs) + ref_ber2 = float(ref_ber2) + ref_tbits2 = int(ref_tbits2) + ref_terrs2 = int(ref_terrs2) + + # Read stm log + print("Target") + with open("stdout.log", "r") as f: + for line in f: + if (line[0:4] == "BER2"): + print(line, end="") + _, tgt_ber2, _, tgt_tbits2, _, tgt_terrs2 = line.split() + elif (line[0:3] == "BER"): + print(line, end="") + _, tgt_ber, _, tgt_tbits, _, tgt_terrs = line.split() + elif (line[0:9] == "Coded BER"): + print(line, end="") + _, _, tgt_ber2, _, tgt_tbits2, _, tgt_terrs2 = line.split() + # Strings to integers + tgt_ber = float(tgt_ber) + tgt_tbits = int(tgt_tbits) + tgt_terrs = int(tgt_terrs) + tgt_ber2 = float(tgt_ber2) + tgt_tbits2 = int(tgt_tbits2) + tgt_terrs2 = int(tgt_terrs2) + + # simple hack to tolerate zero bits > NAN + if (math.isnan(ref_ber2)): ref_ber2 = 0 + if (math.isnan(tgt_ber2)): tgt_ber2 = 0 + + ## Max BER values + if ((tgt_ber > max_ber) or (tgt_ber2 > max_ber2)): + fails += 1 + print("FAIL: max BER") + else: + print("PASS: max BER") + + ## Compare BER values + if (compare_ber): + chk_tolerance_ber = abs(ref_ber - tgt_ber) + chk_tolerance_tbits = abs(ref_tbits - tgt_tbits) + chk_tolerance_terrs = abs(ref_terrs - tgt_terrs) + chk_tolerance_ber2 = abs(ref_ber2 - tgt_ber2) + chk_tolerance_tbits2 = abs(ref_tbits2 - tgt_tbits2) + chk_tolerance_terrs2 = abs(ref_terrs2 - tgt_terrs2) + passes = True + + if (chk_tolerance_ber > tolerance_ber): + print("fail tolerance_ber {} > {}". + format(chk_tolerance_ber, tolerance_ber)) + passes = False + if (chk_tolerance_tbits > tolerance_tbits): + print("fail tolerance_tbits {} > {}". + format(chk_tolerance_tbits, tolerance_tbits)) + passes = False + if (chk_tolerance_terrs > tolerance_terrs): + print("fail tolerance_terrs {} > {}". + format(chk_tolerance_terrs, tolerance_terrs)) + passes = False + if (ref_tbits2 == 0): + if (chk_tolerance_ber2 > tolerance_ber2): + print("fail tolerance_ber2 {} > {}". + format(chk_tolerance_ber2, tolerance_ber2)) + passes = False + if (chk_tolerance_tbits2 > tolerance_tbits): + print("fail tolerance_tbits2 {} > {}". + format(chk_tolerance_tbits2, tolerance_tbits)) + passes = False + if (chk_tolerance_terrs2 > tolerance_terrs): + print("fail tolerance_terrs2 {} > {}". + format(chk_tolerance_terrs2, tolerance_terrs)) + passes = False + + if (passes): + print("PASS: BER compare") + else: + fails += 1 + print("FAIL: BER compare") + + # end Compare BER + # end BER checks + +#### Output differences +if (compare_output): + + print("\nOutput checks") + + # Output is a binary file of bytes whose values are 0x00 or 0x01. + with open("ref_demod_out.raw", "rb") as f: ref_out_bytes = f.read() + with open("stm_out.raw", "rb") as f: tgt_out_bytes = f.read() + if (len(ref_out_bytes) != len(tgt_out_bytes)): + fails += 1 + print("FAIL Output, length mismatch") + else: + output_diffs = 0 + for i in range(len(ref_out_bytes)): + fnum = math.floor(i/Nbitsperframe) + bnum = i - (fnum * Nbitsperframe) + # Both legal values?? + if (ref_out_bytes[i] > 1): + print("Error: Output frame {} byte {} not 0 or 1 in reference data".format(fnum, bnum)) + fails += 1 + if (tgt_out_bytes[i] > 1): + print("Error: Output frame {} byte {} not 0 or 1 in target data".format(fnum, bnum)) + fails += 1 + # Match?? + if (ref_out_bytes[i] != tgt_out_bytes[i]): + print("Output frame {} byte {} mismatch: ref={} tgt={}".format( + fnum, bnum, ref_out_bytes[i], tgt_out_bytes[i])) + output_diffs += 1 + # end for i + if (output_diffs > tolerance_output_differences): + print("FAIL: Output Differences = {}".format(output_diffs)) + fails += 1 + else: + print("PASS: Output Differences = {}".format(output_diffs)) + # end not length mismatch + + + #### Syms data + if (config_log_payload_syms): + print("\nSyms and Amps checks") + + fref = open("ofdm_demod_ref_log.txt", "r") + fdiag = open("stm_diag.raw", "rb") + + ref_data = read_octave_text(fref) + (tgt_syms, tgt_amps) = read_tgt_syms(fdiag) + fdiag.close() + write_syms_as_octave(tgt_syms, tgt_amps) # for manual debug... + + # Find smallest common subset + hgt = min(tgt_syms.shape[0], ref_data["payload_syms_log_c"].shape[0]) + wid = min(tgt_syms.shape[1], ref_data["payload_syms_log_c"].shape[1]) + + ref_syms = ref_data["payload_syms_log_c"][:hgt][:wid] + ref_amps = ref_data["payload_amps_log_c"][:hgt][:wid] + tgt_syms= tgt_syms[:hgt][:wid] + tgt_amps= tgt_amps[:hgt][:wid] + + # Eliminate trailing rows of all zeros + # Sum the rows to find rows of all zeros + row_sums = ref_syms.sum(axis=1) + tgt_syms.sum(axis=1) + nonzeros = row_sums.nonzero() + last_nonzero = nonzeros[0][-1] + # stop index is 1 past the last!! + # and use the Magnitude of the complex values + ref_syms = np.abs(ref_syms[:last_nonzero+1]) + ref_amps = np.abs(ref_amps[:last_nonzero+1]) + tgt_syms = np.abs(tgt_syms[:last_nonzero+1]) + tgt_amps = np.abs(tgt_amps[:last_nonzero+1]) + + # Differences - Syms + #diffs_syms = np.abs(ref_syms - tgt_syms) # This is the mag of complex + diffs_syms = np.abs(np.divide((ref_syms - tgt_syms), ref_syms, + where=(ref_syms!=0))) + print("Minimum syms difference = {:.6f}".format(np.amin(diffs_syms))) + print("Maximum syms difference = {:.6f}".format(np.amax(diffs_syms))) + print("Average syms difference = {:.6f}".format(np.average(diffs_syms))) + if (args.verbose): # Print top 10 differences + diffs_syms_sorted_indexes = (diffs_syms).argsort(axis=None)[::-1] + print(" Top 10 differences") + for i in range(10): + j = diffs_syms_sorted_indexes[i] + print(" #{} @{}: {} <?> {} = {:.6f}".format( + i, j, + ref_syms.flatten()[j], tgt_syms.flatten()[j], diffs_syms.flatten()[j]) + ) + # Errors are differences > tolerance_syms + errors_syms = diffs_syms - tolerance_syms + errors_syms[errors_syms < 0.0] = 0.0 + num_errors_syms = np.count_nonzero(errors_syms) + error_rows_syms = np.amax(errors_syms, axis=1) + num_error_rows_syms = np.count_nonzero(error_rows_syms) + print("") + print("{} symbol errors on {} rows".format(num_errors_syms, num_error_rows_syms)) + + # Differences - Amps + diffs_amps = np.abs(np.divide((ref_amps - tgt_amps), ref_amps, + where=(ref_amps!=0))) + print("Minimum amps difference = {:.6f}".format(np.amin(diffs_amps))) + print("Maximum amps difference = {:.6f}".format(np.amax(diffs_amps))) + print("Average amps difference = {:.6f}".format(np.average(diffs_amps))) + if (args.verbose): # Print top 10 differences + diffs_amps_sorted_indexes = (diffs_amps).argsort(axis=None)[::-1] + print(" Top 10 differences") + for i in range(10): + j = diffs_amps_sorted_indexes[i] + print(" #{} @{}: {} <?> {} = {:.6f}".format( + i, j, + ref_amps.flatten()[j], tgt_amps.flatten()[j], diffs_amps.flatten()[j]) + ) + + # Errors are differences > tolerance_syms + errors_amps = diffs_amps - tolerance_amps + errors_amps[errors_amps < 0.0] = 0.0 + num_errors_amps = np.count_nonzero(errors_amps) + error_rows_amps = np.amax(errors_amps, axis=1) + num_error_rows_amps = np.count_nonzero(error_rows_amps) + print("") + print("{} Amplitude errors on {} rows".format(num_errors_amps, num_error_rows_amps)) + # End compare_output + + +#### Profile +if (config_profile): + print("\nProfile:") + with open("stdout.log", "r") as f: + sum_profiles.sum_profiles(f, 100) + + print("\nStack:") + with open("stdout.txt", "r") as f: + for line in f: + if (line.startswith("Max stack")): + print(line) + + +#### Print final status message +if (fails): print("\nTest FAILED!") +else: print("\nTest PASSED") + +sys.exit(fails) diff --git a/stm32/unittest/scripts/tst_ofdm_demod_setup b/stm32/unittest/scripts/tst_ofdm_demod_setup new file mode 100755 index 0000000..d7c43e9 --- /dev/null +++ b/stm32/unittest/scripts/tst_ofdm_demod_setup @@ -0,0 +1,100 @@ +#!/bin/bash -x +# +# tst_ofdm_demod_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + quick ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "01000000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out stm_in.raw --testframes 10 > setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + ideal ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "01000000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out stm_in.raw --testframes 10 > setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + AWGN ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "11000000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 10 > setup.log 2>&1 + cohpsk_ch mod_bits.raw stm_in.raw -20 --Fs 8000 -f -5 >> setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + fade ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "11000000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 60 > setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -24.5 -f -10 --mpp \ + --fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + profile ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "00001000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 100 > setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -20 -f -10 --mpp \ + --fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + ldpc ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "01110000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out stm_in.raw --testframes 1 --ldpc 1 > setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + ldpc_AWGN ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "01110000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 30 --ldpc 1 > setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -20 -f -10 >> setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + ldpc_fade ) + # Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile> + echo "01110000" > stm_cfg.txt + ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 120 --ldpc 1 > setup.log 2>&1 + ch mod_bits.raw stm_in.raw --No -30 -f -10 --mpp \ + --fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1 + ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \ + --testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1; + ;; + + esac diff --git a/stm32/unittest/scripts/tst_ofdm_mod_check b/stm32/unittest/scripts/tst_ofdm_mod_check new file mode 100755 index 0000000..d3b45bf --- /dev/null +++ b/stm32/unittest/scripts/tst_ofdm_mod_check @@ -0,0 +1,65 @@ +#!/bin/bash -x +# +# tst_ofdm_mod_check +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test CHECK actions: + +declare -i Fails=0 + +case "${TEST_OPT}" in + + plain) LDPC="";; + ldpc) LDPC="--ldpc";; + esac + +echo -e "\nReference check" +if ofdm_demod --in ref_mod_out.raw --out ref_ofdm_demod.raw --testframes ${LDPC}; then + echo "Passed" +else + echo "Failed" + let Fails=($Fails + 1) +fi +# +echo -e "\nTarget check" +if ofdm_demod --in mod.raw --out stm_demod.raw --testframes ${LDPC}; then + echo "Passed" +else + echo "Failed" + let Fails=($Fails + 1) +fi +# +echo -e "\nCompare output binary data" +if compare_ints -s -b2 -t3 ref_mod_out.raw mod.raw; then + echo "Passed" +else + echo "Failed" + let Fails=($Fails + 1) +fi +# + +if (( $Fails == 0 )); then + echo -e "\nTest PASSED" +else + echo -e "\nTest FAILED!" +fi + +exit $Fails diff --git a/stm32/unittest/scripts/tst_ofdm_mod_setup b/stm32/unittest/scripts/tst_ofdm_mod_setup new file mode 100755 index 0000000..d81b407 --- /dev/null +++ b/stm32/unittest/scripts/tst_ofdm_mod_setup @@ -0,0 +1,42 @@ +#!/bin/bash +# +# tst_ofdm_mod_setup +# +# Setup input and reference data for one of several versions of this test. + +# Find the scripts directory +SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" + +# Setup common variables +source $SCRIPTS/run_tests_common.sh + +# RUN_DIR - Directory where test will be run +RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}" + +# Call common setup function to make the directory +setup_common "${RUN_DIR}" + +# Change to test directory +cd "${RUN_DIR}" + + +##################################################################### +## Test SETUP actions: + +case "${TEST_OPT}" in + + plain ) + # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile> + echo "00000000" > stm_cfg.txt + ofdm_get_test_bits --out stm_in.raw --frames 10 --verbose > setup.log 2>&1 + ofdm_mod --in stm_in.raw --out ref_mod_out.raw --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + ldpc ) + # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile> + echo "00100000" > stm_cfg.txt + ofdm_get_test_bits --out stm_in.raw --frames 10 --length 112 --verbose > setup.log 2>&1 + ofdm_mod --in stm_in.raw --out ref_mod_out.raw --ldpc --verbose 1 > ref_gen_log.txt 2>&1 + ;; + + esac diff --git a/stm32/unittest/src/CMakeLists.txt b/stm32/unittest/src/CMakeLists.txt new file mode 100644 index 0000000..7b2f161 --- /dev/null +++ b/stm32/unittest/src/CMakeLists.txt @@ -0,0 +1,161 @@ +set(STM32F4_SYSTEM_SRCS +../../src/system_stm32f4xx.c +../../src/memtools.c +../../src/stm32f4_machdep.c +startup_stm32f4xx.s +) + +list(APPEND SEMIHOSTING_SRCS semihosting.c ${STM32F4_SYSTEM_SRCS}) +list(APPEND SEMIHOSTING_PROFILE_LIBS codec2_prof stm32f4 CMSIS rdimon) +list(APPEND SEMIHOSTING_LIBS codec2 stm32f4 CMSIS rdimon) + +macro(profiledSemihostedBin target) + add_mapped_executable(${target} ${target}.c ${SEMIHOSTING_SRCS}) + target_link_libraries(${target} ${SEMIHOSTING_PROFILE_LIBS}) + target_compile_definitions(${target} PRIVATE "-DPROFILE -DSEMIHOST_USE_STDIO --specs=rdimon.specs") + elf2bin(${target}) +endmacro() + +macro(semihostedBin target) + add_mapped_executable(${target} ${target}.c ${SEMIHOSTING_SRCS}) + target_link_libraries(${target} ${SEMIHOSTING_LIBS}) + target_compile_definitions(${target} PRIVATE "-DSEMIHOST_USE_STDIO --specs=rdimon.specs") + elf2bin(${target}) +endmacro() + +semihostedBin(tst_api_tx) +semihostedBin(tst_codec2_enc) +semihostedBin(tst_codec2_dec) +semihostedBin(tst_ofdm_mod) +profiledSemihostedBin(tst_ofdm_demod) +semihostedBin(tst_ldpc_enc) +semihostedBin(tst_ldpc_dec) +semihostedBin(tst_api_mod) +profiledsemihostedBin(tst_api_demod) +semihostedBin(tst_semihost) +semihostedBin(tst_codec2_fft_init) + + +add_test(NAME check_ram_limit + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/check_ram_limit + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +add_test(NAME tst_ldpc_enc + COMMAND sh -c "./run_stm32_tst tst_ldpc_enc ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_ldpc_dec_ideal + COMMAND sh -c "./run_stm32_tst tst_ldpc_dec ideal ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_ldpc_dec_noise + COMMAND sh -c "./run_stm32_tst tst_ldpc_dec noise ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ldpc_dec_noise PROPERTIES DEPENDS tst_ldpc_dec_ideal) + +add_test(NAME tst_ofdm_mod_plain + COMMAND sh -c "./run_stm32_tst tst_ofdm_mod plain ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_ofdm_mod_ldpc + COMMAND sh -c "./run_stm32_tst tst_ofdm_mod ldpc ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_mod_ldpc PROPERTIES DEPENDS tst_ofdm_mod_plain) + +add_test(NAME tst_ofdm_demod_quick + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod quick ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_ofdm_demod_ideal + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ideal ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_ideal PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_ofdm_demod_AWGN + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod AWGN ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_AWGN PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_ofdm_demod_fade + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod fade ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_fade PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_ofdm_demod_ldpc + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_ldpc PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_ofdm_demod_ldpc_AWGN + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc_AWGN ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_ldpc_AWGN PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_ofdm_demod_ldpc_fade + COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc_fade ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_ofdm_demod_ldpc_fade PROPERTIES DEPENDS tst_ofdm_demod_quick) + +add_test(NAME tst_codec2_enc_1300 + COMMAND sh -c "./run_stm32_tst tst_codec2_enc 1300 ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_codec2_enc_700C + COMMAND sh -c "./run_stm32_tst tst_codec2_enc 700C ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_codec2_enc_700C PROPERTIES DEPENDS tst_codec2_enc_1300) + + +add_test(NAME tst_codec2_dec_1300 + COMMAND sh -c "./run_stm32_tst tst_codec2_dec 1300 ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_codec2_dec_700C + COMMAND sh -c "./run_stm32_tst tst_codec2_dec 700C ${UT_PARAMS} " + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) +set_tests_properties(tst_codec2_dec_700C PROPERTIES DEPENDS tst_codec2_dec_1300) + +add_test(NAME tst_api_mod_700D_TEST + COMMAND sh -c "./run_stm32_tst tst_api_mod 700D_TEST ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_mod_700D_CODEC + COMMAND sh -c "./run_stm32_tst tst_api_mod 700D_CODEC ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_mod_700E_TEST + COMMAND sh -c "./run_stm32_tst tst_api_mod 700E_TEST ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_mod_700E_CODEC + COMMAND sh -c "./run_stm32_tst tst_api_mod 700E_CODEC ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700D_plain_test + COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_plain_test ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700D_AWGN_test + COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_AWGN_test ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700D_AWGN_codec + COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_AWGN_codec ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700E_plain_test + COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_plain_test ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700E_AWGN_test + COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_AWGN_test ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_700E_AWGN_codec + COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_AWGN_codec ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + +add_test(NAME tst_api_demod_1600_plain_codec + COMMAND sh -c "./run_stm32_tst tst_api_demod 1600_plain_codec ${UT_PARAMS}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts) + diff --git a/stm32/unittest/src/Makefile b/stm32/unittest/src/Makefile new file mode 100644 index 0000000..5b0ed14 --- /dev/null +++ b/stm32/unittest/src/Makefile @@ -0,0 +1,745 @@ +# Makefile for stm32f4 Codec 2 unittest programs + +# Include local definitions if they exist. +-include local.mak + +################################################### + +FLOAT_TYPE=hard + +################################################### + +CROSS_COMPILE ?= arm-none-eabi- +CC=$(BINPATH)$(CROSS_COMPILE)gcc +AS=$(BINPATH)$(CROSS_COMPILE)as +OBJCOPY=$(BINPATH)$(CROSS_COMPILE)objcopy +SIZE=$(BINPATH)$(CROSS_COMPILE)size +SUDO ?= sudo + +################################################### + +CFLAGS = -std=gnu11 -O2 -g -Wall -DSTM32F40_41xxx -DCORTEX_M4 +CFLAGS += -mlittle-endian -mthumb -mthumb-interwork -nostartfiles -mcpu=cortex-m4 -Wno-unused-function + +ifeq ($(FLOAT_TYPE), hard) +CFLAGS += -fsingle-precision-constant -Wdouble-promotion +CFLAGS += -fdata-sections -ffunction-sections -Xlinker --gc-sections +CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard -D__FPU_PRESENT=1 -D__FPU_USED=1 +else +CFLAGS += -msoft-float +endif + +#CFLAGS += -DDEBUG_ALLOC + +################################################### +# STM32F4 Standard Peripheral Library + +PERIPHLIBDIR ?= STM32F4xx_DSP_StdPeriph_Lib +CMSIS = $(PERIPHLIBDIR)/Libraries/CMSIS +STM32F4LIB = $(PERIPHLIBDIR)/Libraries/STM32F4xx_StdPeriph_Driver +STM32F4TEMPLATE = $(PERIPHLIBDIR)/Project/STM32F4xx_StdPeriph_Templates +DSPLIB = $(PERIPHLIBDIR)/Libraries/CMSIS/DSP_Lib + +CFLAGS += -DUSE_STDPERIPH_DRIVER -I$(STM32F4LIB)/inc -I$(STM32F4TEMPLATE) +CFLAGS += -I$(CMSIS)/Include -I$(CMSIS)/Device/ST/STM32F4xx/Include +CFLAGS += -DARM_MATH_CM4 +CFLAGS += -DFDV_ARM_MATH +CFLAGS += -DSEMIHOST_USE_STDIO + +# Precious files that should be preserved at all cost! +.PRECIOUS: dl/$(PERIPHLIBZIP) + +STM32F4LIB_SRCS=\ +$(STM32F4LIB)/src/misc.c\ +$(STM32F4LIB)/src/stm32f4xx_adc.c\ +$(STM32F4LIB)/src/stm32f4xx_can.c\ +$(STM32F4LIB)/src/stm32f4xx_cec.c\ +$(STM32F4LIB)/src/stm32f4xx_crc.c\ +$(STM32F4LIB)/src/stm32f4xx_cryp_aes.c\ +$(STM32F4LIB)/src/stm32f4xx_cryp.c\ +$(STM32F4LIB)/src/stm32f4xx_cryp_des.c\ +$(STM32F4LIB)/src/stm32f4xx_cryp_tdes.c\ +$(STM32F4LIB)/src/stm32f4xx_dac.c\ +$(STM32F4LIB)/src/stm32f4xx_dbgmcu.c\ +$(STM32F4LIB)/src/stm32f4xx_dcmi.c\ +$(STM32F4LIB)/src/stm32f4xx_dma2d.c\ +$(STM32F4LIB)/src/stm32f4xx_dma.c\ +$(STM32F4LIB)/src/stm32f4xx_exti.c\ +$(STM32F4LIB)/src/stm32f4xx_flash.c\ +$(STM32F4LIB)/src/stm32f4xx_flash_ramfunc.c\ +$(STM32F4LIB)/src/stm32f4xx_fmpi2c.c\ +$(STM32F4LIB)/src/stm32f4xx_fsmc.c\ +$(STM32F4LIB)/src/stm32f4xx_gpio.c\ +$(STM32F4LIB)/src/stm32f4xx_hash.c\ +$(STM32F4LIB)/src/stm32f4xx_hash_md5.c\ +$(STM32F4LIB)/src/stm32f4xx_hash_sha1.c\ +$(STM32F4LIB)/src/stm32f4xx_i2c.c\ +$(STM32F4LIB)/src/stm32f4xx_iwdg.c\ +$(STM32F4LIB)/src/stm32f4xx_ltdc.c\ +$(STM32F4LIB)/src/stm32f4xx_pwr.c\ +$(STM32F4LIB)/src/stm32f4xx_qspi.c\ +$(STM32F4LIB)/src/stm32f4xx_rcc.c\ +$(STM32F4LIB)/src/stm32f4xx_rng.c\ +$(STM32F4LIB)/src/stm32f4xx_rtc.c\ +$(STM32F4LIB)/src/stm32f4xx_sai.c\ +$(STM32F4LIB)/src/stm32f4xx_sdio.c\ +$(STM32F4LIB)/src/stm32f4xx_spdifrx.c\ +$(STM32F4LIB)/src/stm32f4xx_spi.c\ +$(STM32F4LIB)/src/stm32f4xx_syscfg.c\ +$(STM32F4LIB)/src/stm32f4xx_tim.c\ +$(STM32F4LIB)/src/stm32f4xx_usart.c\ +$(STM32F4LIB)/src/stm32f4xx_wwdg.c + +STM32F4LIB_OBJS = $(STM32F4LIB_SRCS:.c=.o) + +CMSIS_SRCS=\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q7.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_f32.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q15.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q31.c\ +$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q7.c\ +$(CMSIS)/DSP_Lib/Source/CommonTables/arm_common_tables.c\ +$(CMSIS)/DSP_Lib/Source/CommonTables/arm_const_structs.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c\ +$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_f32.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q15.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q31.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_f32.c\ +$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_q31.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_f32.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_q15.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_q31.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_f32.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_q15.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_q31.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q7.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q31.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_q15.c\ +$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f64.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q31.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_f32.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q15.c\ +$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q7.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q7.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q7.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q7.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_q31.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_f32.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_q15.c\ +$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_q31.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_f32.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q15.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q31.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q7.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_f32.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q15.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q31.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q7.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q15.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q31.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q7.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_float.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_q31.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_q7.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_float.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_q15.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_q7.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_float.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_q15.c\ +$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_bitreversal.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix8_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_f32.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q31.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_q15.c\ +$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_q31.c\ + +CMSIS_OBJS = $(CMSIS_SRCS:.c=.o) $(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_bitreversal2.o + +################################################### +# Codec 2 + +CODEC2_DIR = ../../.. +CODEC2_SRC = $(CODEC2_DIR)/src +CODEC2_BLD = $(CODEC2_DIR)/build_linux + +CODEC2_SRCS=\ +$(CODEC2_SRC)/lpc.c \ +$(CODEC2_SRC)/nlp.c \ +$(CODEC2_SRC)/postfilter.c \ +$(CODEC2_SRC)/sine.c \ +$(CODEC2_SRC)/codec2.c \ +$(CODEC2_SRC)/codec2_fft.c \ +$(CODEC2_SRC)/cohpsk.c \ +$(CODEC2_SRC)/linreg.c \ +$(CODEC2_SRC)/kiss_fft.c \ +$(CODEC2_SRC)/kiss_fftr.c \ +$(CODEC2_SRC)/interp.c \ +$(CODEC2_SRC)/lsp.c \ +$(CODEC2_SRC)/mbest.c \ +$(CODEC2_SRC)/newamp1.c \ +$(CODEC2_SRC)/phase.c \ +$(CODEC2_SRC)/quantise.c \ +$(CODEC2_SRC)/pack.c \ +$(CODEC2_SRC)/codebook.c \ +$(CODEC2_SRC)/codebookd.c \ +$(CODEC2_SRC)/codebookjvm.c \ +$(CODEC2_SRC)/codebookge.c \ +$(CODEC2_SRC)/codebooknewamp1.c \ +$(CODEC2_SRC)/codebooknewamp1_energy.c \ +$(CODEC2_SRC)/dump.c \ +$(CODEC2_SRC)/fdmdv.c \ +$(CODEC2_SRC)/freedv_api.c \ +$(CODEC2_SRC)/filter.c \ +$(CODEC2_SRC)/varicode.c \ +$(CODEC2_SRC)/golay23.c \ +$(CODEC2_SRC)/fsk.c \ +$(CODEC2_SRC)/fmfsk.c \ +$(CODEC2_SRC)/freedv_vhf_framing.c \ +$(CODEC2_SRC)/freedv_data_channel.c \ +$(CODEC2_SRC)/ofdm.c \ +$(CODEC2_SRC)/phi0.c \ +$(CODEC2_SRC)/mpdecode_core.c \ +$(CODEC2_SRC)/gp_interleaver.c \ +$(CODEC2_SRC)/interldpc.c \ +$(CODEC2_SRC)/HRA_112_112.c \ + +CFLAGS += -D__EMBEDDED__ +CFLAGS += -I$(CODEC2_SRC) +CFLAGS += -I$(CODEC2_BLD) + +################################################### +# Codec2/STM32 + +CODEC2_STM32_DIR := ../.. +CODEC2_STM32_SRC = $(CODEC2_STM32_DIR)/src +CODEC2_STM32_HDR = $(CODEC2_STM32_DIR)/inc +CFLAGS += -I$(CODEC2_STM32_HDR) +CFLAGS += -T$(CODEC2_STM32_DIR)/stm32_flash.ld + +#enable this for dump files to help verify optimisation +#CFLAGS += -DDUMP +ASFLAGS += $(CFLAGS) + +################################################### + +ROOT=$(shell pwd) + +# Library paths + +LIBPATHS = + +# Libraries to link + +# Standard ARM semihosting +LIBS = -lg -lrdimon -lm --specs=rdimon.specs + +# startup file + +SRCS += startup_stm32f4xx.s +SRCS += init.c +SRCS += stm32f4_machdep.c +SRCS += $(CODEC2_STM32_SRC)/system_stm32f4xx.c + +all: libstm32f4.a \ + tst_codec2_enc.bin tst_codec2_dec.bin \ + tst_ofdm_mod.bin tst_ofdm_demod.bin \ + tst_ldpc_enc.bin tst_ldpc_dec.bin \ + tst_api_mod.bin tst_api_demod.bin \ + tst_semihost.bin \ + tst_codec2_fft_init.bin + +libstm32f4.a: $(CMSIS_OBJS) $(STM32F4LIB_OBJS) + find -L $(PERIPHLIBDIR) -type f -name '*.o' -exec $(AR) crs libstm32f4.a {} ";" + +# Kludgy target to build a file with CFLAGS -DPROFILE +%.profile.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $< + +# Rule for building .bin files from a .elf +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +#####%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#### +##### Used for debugging stdio (with semihosting) : +## +## TMP_NEWLIB_INCS = -INewlib +## TMP_NEWLIB_DEFS = -DARM_RDI_MONITOR +## TMP_NEWLIB_OBJS = Newlib/fread.o Newlib/refill.o Newlib/syscalls.o Newlib/stdio.o Newlib/readr.o Newlib/fclose.o Newlib/fflush.o +## +## Newlib/fread.o: Newlib/fread.c +## $(CC) -c $(CFLAGS) $^ -o Newlib/fread.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS) +## +## Newlib/refill.o: Newlib/refill.c +## $(CC) -c $(CFLAGS) $^ -o Newlib/refill.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS) +## +## Newlib/syscalls.o: Newlib/syscalls.c +## $(CC) -c $(CFLAGS) $^ -o Newlib/syscalls.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS) +## +## Newlib/stdio.o: Newlib/stdio.c +## $(CC) -c $(CFLAGS) $^ -o Newlib/stdio.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS) +## +## Newlib/readr.o: Newlib/readr.c +## $(CC) -c $(CFLAGS) $^ -o Newlib/readr.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS) +## +#####%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#### + +#################################################### +# Test Programs + +# ----------------------------------------------- +TST_API_TX_SRCS=\ +tst_api_tx.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c + +TST_API_TX_SRCS += $(CODEC2_SRCS) +TST_API_TX_SRCS += $(SRCS) + +tst_api_tx.elf: $(TST_API_TX_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +TST_CODEC2_ENC_SRCS=\ +tst_codec2_enc.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_CODEC2_ENC_SRCS += $(CODEC2_SRCS) +TST_CODEC2_ENC_SRCS += $(SRCS) +# +tst_codec2_enc.elf: $(TST_CODEC2_ENC_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_codec2_enc.map + +# ----------------------------------------------- +TST_CODEC2_DEC_SRCS=\ +tst_codec2_dec.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_CODEC2_DEC_SRCS += $(CODEC2_SRCS) +TST_CODEC2_DEC_SRCS += $(SRCS) +# +tst_codec2_dec.elf: $(TST_CODEC2_DEC_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +TST_API_MOD_SRCS=\ +tst_api_mod.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_API_MOD_SRCS += $(CODEC2_SRCS) +TST_API_MOD_SRCS += $(SRCS) +# +tst_api_mod.elf: $(TST_API_MOD_SRCS:.c=.profile.o) libstm32f4.a # $(TMP_NEWLIB_OBJS) + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +# TST_API_MOD_700D_PROFILE +# +TST_API_MOD_700D_PROFILE_SRCS=\ +tst_api_mod_700d_profile.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_API_MOD_700D_PROFILE_SRCS += $(CODEC2_SRCS) +TST_API_MOD_700D_PROFILE_SRCS += $(SRCS) +# +tst_api_mod_700d_profile.elf: $(TST_API_MOD_700D_PROFILE_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +# TST_API_DEMOD +TST_API_DEMOD_SRCS=\ +tst_api_demod.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +## (for debug use) sbrk_dbg.c \ +# +TST_API_DEMOD_SRCS += $(CODEC2_SRCS) +TST_API_DEMOD_SRCS += $(SRCS) +# +tst_api_demod.elf: $(TST_API_DEMOD_SRCS:.c=.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_api_demod.map + +# ----------------------------------------------- +# TST_API_DEMOD_700D_PROFILE +api_demod_700d_in_10f: + # Each frame of OFDM is 160ms which is 1280 speech samples of 2 bytes each. + # + dd bs=2560 count=100 if=../../../raw/hts1.raw of=tmp_spch_in.raw + cohpsk_ch tmp_spch_in.raw tmp_modout.raw -20 -Fs 8000 -f -5 --raw_dir ../../../raw + freedv_tx 700D tmp_modout.raw api_demod_700d_in_10f --txbpf 0 +# +api_demod_700d_in_10f.c: api_demod_700d_in_10f + xxd -i api_demod_700d_in_10f > api_demod_700d_in_10f.c +# +TST_API_DEMOD_700D_PROFILE_SRCS=\ +tst_api_demod_700d_profile.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +## (for debug use) sbrk_dbg.c \ +# +tst_api_demod_700d_profile.profile.o: tst_api_demod_700d_profile.c api_demod_700d_in_10f.c + $(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $< +# +TST_API_DEMOD_700D_PROFILE_SRCS += $(CODEC2_SRCS) +TST_API_DEMOD_700D_PROFILE_SRCS += $(SRCS) +# +tst_api_demod_700d_profile.elf: $(TST_API_DEMOD_700D_PROFILE_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +TST_OFDM_MOD_SRCS=\ +tst_ofdm_mod.c \ +semihosting.c \ +$(CODEC2_SRC)/ofdm.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c + +TST_OFDM_MOD_SRCS += $(CODEC2_SRCS) +TST_OFDM_MOD_SRCS += $(SRCS) + +tst_ofdm_mod.elf: $(TST_OFDM_MOD_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +TST_OFDM_DEMOD_SRCS=\ +tst_ofdm_demod.c \ +semihosting.c \ +$(CODEC2_SRC)/ofdm.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_OFDM_DEMOD_SRCS += $(CODEC2_SRCS) +TST_OFDM_DEMOD_SRCS += $(SRCS) +# +tst_ofdm_demod.elf: $(TST_OFDM_DEMOD_SRCS:.c=.profile.o) libstm32f4.a + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_demod.map + +# ----------------------------------------------- +# TST_OFDM_MOD_STACK +# +ofdm_mod_ref_10f: + $(CODEC2_BLD)/src/ofdm_mod /dev/zero ofdm_mod_ref_10f --testframes 1 --ldpc +# +ofdm_mod_ref_10f.c: ofdm_mod_ref_10f + xxd -g2 -e -i ofdm_mod_ref_10f > ofdm_mod_ref_10f.c +# +tst_ofdm_mod_stack.profile.o: tst_ofdm_mod_stack.c ofdm_mod_ref_10f.c + $(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $< +# +TST_OFDM_MOD_STACK_SRCS=\ +tst_ofdm_mod_stack.c \ +function_trace.c \ +$(CODEC2_SRC)/ofdm.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_OFDM_MOD_STACK_SRCS += $(CODEC2_SRCS) +TST_OFDM_MOD_STACK_SRCS += $(SRCS) +# +tst_ofdm_mod_stack.elf: $(TST_OFDM_MOD_STACK_SRCS:.c=.o) libstm32f4.a + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_mod_stack.map + +# ----------------------------------------------- +# TST_OFDM_DEMOD_STACK +ofdm_demod_in_10f: + $(CODEC2_BLD)/src/ofdm_get_test_bits - -f 10 | \ + $(CODEC2_BLD)/src/ofdm_mod - ofdm_demod_in_10f +# +ofdm_demod_in_10f.c: ofdm_demod_in_10f + xxd -i ofdm_demod_in_10f > ofdm_demod_in_10f.c +# +ofdm_demod_ref_10f: ofdm_demod_in_10f + $(CODEC2_BLD)/src/ofdm_demod ofdm_demod_in_10f ofdm_demod_ref_10f +# +ofdm_demod_ref_10f.c: ofdm_demod_ref_10f + xxd -i ofdm_demod_ref_10f > ofdm_demod_ref_10f.c +# +tst_ofdm_demod_stack.o: ofdm_demod_in_10f.c ofdm_demod_ref_10f.c +# +TST_OFDM_DEMOD_STACK_SRCS=\ +tst_ofdm_demod_stack.c \ +$(CODEC2_SRC)/ofdm.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_OFDM_DEMOD_STACK_SRCS += $(CODEC2_SRCS) +TST_OFDM_DEMOD_STACK_SRCS += $(SRCS) +# +tst_ofdm_demod_stack.elf: $(TST_OFDM_DEMOD_STACK_SRCS:.c=.o) libstm32f4.a + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_demod_stack.map + +# ----------------------------------------------- +# Not working yet! +TST_LDPC_ENC_SRCS= \ +tst_ldpc_enc.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_LDPC_ENC_SRCS += $(CODEC2_SRCS) +TST_LDPC_ENC_SRCS += $(SRCS) +# +TST_LDPC_ENC_HDR= \ +$(CODEC2_INC)/mpdecode_code_test.h +# +tst_ldpc_enc.elf: $(TST_LDPC_ENC_SRCS:.c=.profile.o) libstm32f4.a $(TST_LDPC_ENC_HRDS) + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +# Not working yet! +TST_LDPC_DEC_SRCS= \ +tst_ldpc_dec.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_LDPC_DEC_SRCS += $(CODEC2_SRCS) +TST_LDPC_DEC_SRCS += $(SRCS) +# +TST_LDPC_DEC_HDR= \ +$(CODEC2_INC)/mpdecode_code.h +# +tst_ldpc_dec.elf: $(TST_LDPC_DEC_SRCS:.c=.profile.o) libstm32f4.a $(TST_LDPC_DEC_HRDS) + $(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ldpc_dec.map + +# ----------------------------------------------- +TST_SEMIHOST_SRCS=\ +tst_semihost.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_SEMIHOST_SRCS += $(CODEC2_SRCS) +TST_SEMIHOST_SRCS += $(SRCS) +# +tst_semihost.elf: $(TST_SEMIHOST_SRCS:.c=.o) libstm32f4.a #$(TMP_NEWLIB_OBJS) + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) + +# ----------------------------------------------- +TST_CODEC2_FFT_INIT_SRCS=\ +tst_codec2_fft_init.c \ +semihosting.c \ +$(CODEC2_STM32_SRC)/system_stm32f4xx.c +# +TST_CODEC2_FFT_INIT_SRCS += $(CODEC2_SRCS) +TST_CODEC2_FFT_INIT_SRCS += $(SRCS) +# +tst_codec2_fft_init.elf: $(TST_CODEC2_FFT_INIT_SRCS:.c=.o) libstm32f4.a + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) + + +################################################### + +clean: + rm -f *.elf *.bin + rm -f libstm32f4.a + rm -f $(CMSIS_OBJS) $(STM32F4LIB_OBJS) $(CODEC2_SRC)/*.o + find . -type f -name '*.o' | xargs rm -f diff --git a/stm32/unittest/src/init.c b/stm32/unittest/src/init.c new file mode 100644 index 0000000..527141d --- /dev/null +++ b/stm32/unittest/src/init.c @@ -0,0 +1,10 @@ +/* + * Dummy function to avoid compiler error + */ +void _init() { + +} +void _fini() { + +} + diff --git a/stm32/unittest/src/semihosting.c b/stm32/unittest/src/semihosting.c new file mode 100644 index 0000000..33a929e --- /dev/null +++ b/stm32/unittest/src/semihosting.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> + +#include "semihosting.h" + +extern void initialise_monitor_handles(void); +extern int errno; + +int semihosting_init(void) { + + initialise_monitor_handles(); + setvbuf(stderr, NULL, _IOLBF, 256); + return(0); + +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/semihosting.h b/stm32/unittest/src/semihosting.h new file mode 100644 index 0000000..c602031 --- /dev/null +++ b/stm32/unittest/src/semihosting.h @@ -0,0 +1,7 @@ +#ifndef SEMIHOSTING_H +#define SEMIHOSTING_H +extern int semihosting_init(void); + +#endif // SEMIHOSTING_H + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/startup_stm32f4xx.s b/stm32/unittest/src/startup_stm32f4xx.s new file mode 100644 index 0000000..af31387 --- /dev/null +++ b/stm32/unittest/src/startup_stm32f4xx.s @@ -0,0 +1,529 @@ +/** + ****************************************************************************** + * @file startup_stm32f4xx.s + * @author MCD Application Team + * @version V1.0.0 + * @date 30-September-2011 + * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler +.global EndofMain + +/* 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 + + +/* Fill stack area with a fix pattern for observince max stack use */ + mov r2, r3 + ldr r3, = _estack + ldr r4, =0x55555555 + b LoopFillStack +FillStack: + str r4, [r2], #4 + +LoopFillStack: + cmp r2, r3 + bcc FillStack + + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main +EndofMain: + bl . +.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/stm32/unittest/src/tst_api_demod.c b/stm32/unittest/src/tst_api_demod.c new file mode 100644 index 0000000..3078c00 --- /dev/null +++ b/stm32/unittest/src/tst_api_demod.c @@ -0,0 +1,235 @@ +/*------------------------------------------------------ + + FILE........: tst_api_demod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 7 July 2018 + + Test and profile OFDM de-modulation on the STM32F4. + +-------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* Typical run, using internal testframes: + + # Input + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw + freedv_tx 700D spch_in.raw stm_in.raw --testframes + + # Reference + freedv_rx 700D stm_in.raw ref_demod.raw --testframes + + # Create config + echo "71000010" > stm_cfg.txt + + # Run stm32 + run_stm32_prog ../../src/tst_api_demod.elf --load + + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> + +#include "freedv_api.h" +#include "modem_stats.h" +#include "codec2.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" +#include "memtools.h" + + +struct my_callback_state { + //FILE *ftxt; +}; + +void my_put_next_rx_char(void *callback_state, char c) { + //fprintf(stdout, "text msg: %c\n", c); +} + +void my_put_next_rx_proto(void *callback_state,char *proto_bits){ + //fprintf(stdout, "proto chars: %.*s\n",2, proto_bits); +} + +/* Called when a packet has been received */ +void my_datarx(void *callback_state, unsigned char *packet, size_t size) { + //size_t i; + // + //fprintf(stdout, "data (%zd bytes): ", size); + //for (i = 0; i < size; i++) { + // fprintf(stdout, "0x%02x ", packet[i]); + //} + //fprintf(stdout, "\n"); +} + +/* Called when a new packet can be send */ +void my_datatx(void *callback_state, unsigned char *packet, size_t *size) { + /* This should not happen while receiving.. */ + fprintf(stderr, "datarx callback called, this should not happen!\n"); + *size = 0; +} + +#define SPARE_RAM 3000 + +int main(int argc, char *argv[]) { + char dummy[SPARE_RAM]; + int f_cfg, f_in, f_out; + struct freedv *freedv; + struct my_callback_state my_cb_state; + int frame; + int nread, nin, nout; + int sync; + float snr_est; + + // Force test to fail unless we have this much spare RAM (adjusted by experiment) + memset(dummy, 0, SPARE_RAM); + + semihosting_init(); + PROFILE_VAR(freedv_rx_start); + machdep_profile_init(); + + //////// + // Test configuration, read from stm_cfg.txt + int config_mode; // 0 + int config_testframes; // 1 + int config_verbose; // 6 + //int config_profile; // 7 + char config[8]; + f_cfg = open("stm_cfg.txt", O_RDONLY); + if (f_cfg == -1) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (read(f_cfg, &config[0], 8) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_mode = config[0] - '0'; + if (config_mode == 8) + { + // For the purposes of the UT system, '8' is 700E. + config_mode = FREEDV_MODE_700E; + } + config_testframes = config[1] - '0'; + config_verbose = config[6] - '0'; + //config_profile = config[7] - '0'; + close(f_cfg); + printf("config_mode: %d config_verbose: %d\n", config_mode, config_verbose); + + //////// + freedv = freedv_open(config_mode); + assert(freedv != NULL); + + memtools_find_unused(printf); + + freedv_set_test_frames(freedv, config_testframes); + freedv_set_verbose(freedv, config_verbose); + + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 0); + + short speech_out[freedv_get_n_speech_samples(freedv)]; + short demod_in[freedv_get_n_max_modem_samples(freedv)]; + + freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state); + freedv_set_callback_protocol(freedv, &my_put_next_rx_proto, NULL, &my_cb_state); + freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); + + //////// + // Streams + f_in = open("stm_in.raw", O_RDONLY); + if (f_in == -1) { + perror("Error opening input file\n"); + exit(1); + } + + f_out = open("stm_out.raw", (O_CREAT | O_WRONLY), 0644); + if (f_out == -1) { + perror("Error opening output file\n"); + exit(1); + } + + frame = 0; + + //////// + // Main loop + + nin = freedv_nin(freedv); + while((nread = read(f_in, demod_in, (sizeof(short) * nin))) == (nin * sizeof(short))) { + + fprintf(stderr, "frame: %d, %d bytes read\n", frame, nread); + + PROFILE_SAMPLE(freedv_rx_start); + nout = freedv_rx(freedv, speech_out, demod_in); + PROFILE_SAMPLE_AND_LOG2(freedv_rx_start, " freedv_rx"); + machdep_profile_print_logged_samples(); + + fprintf(stderr, " %d short speech values returned\n", nout); + if (nout) write(f_out, speech_out, (sizeof(short) * nout)); + + if (sync == 0) { + // discard BER results if we get out of sync, helps us get sensible BER results + freedv_set_total_bits(freedv, 0); freedv_set_total_bit_errors(freedv, 0); + freedv_set_total_bits_coded(freedv, 0); freedv_set_total_bit_errors_coded(freedv, 0); + } + freedv_get_modem_stats(freedv, &sync, &snr_est); + int total_bit_errors = freedv_get_total_bit_errors(freedv); + fprintf(stderr, + "frame: %d demod sync: %d nin: %d demod snr: %3.2f dB bit errors: %d\n", + frame, sync, nin, (double)snr_est, total_bit_errors); + + frame++; + nin = freedv_nin(freedv); + } + + ////// + if (freedv_get_test_frames(freedv)) { + int Tbits = freedv_get_total_bits(freedv); + int Terrs = freedv_get_total_bit_errors(freedv); + fprintf(stderr, "BER......: %5.4f Tbits: %5d Terrs: %5d\n", + (double)Terrs/Tbits, Tbits, Terrs); + if (config_mode == FREEDV_MODE_700D || config_mode == FREEDV_MODE_700E) { + int Tbits_coded = freedv_get_total_bits_coded(freedv); + int Terrs_coded = freedv_get_total_bit_errors_coded(freedv); + fprintf(stderr, "Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", + (double)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded); + } + } + + printf("Done\n"); + + close(f_in); + close(f_out); + + memtools_find_unused(printf); + printf("\nEnd of Test\n"); +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_api_demod_700d_profile.c b/stm32/unittest/src/tst_api_demod_700d_profile.c new file mode 100644 index 0000000..4f3dfbe --- /dev/null +++ b/stm32/unittest/src/tst_api_demod_700d_profile.c @@ -0,0 +1,136 @@ +/*------------------------------------------------------ + + FILE........: tst_api_demod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 7 July 2018 + + Test and profile OFDM de-modulation on the STM32F4. + +-------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> + +#include "freedv_api.h" +#include "modem_stats.h" +#include "codec2.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + + +/* Input and Reference data */ +const +#include "api_demod_700d_in_10f.c" + +struct my_callback_state { + //FILE *ftxt; +}; + +void my_put_next_rx_char(void *callback_state, char c) { + //fprintf(stdout, "text msg: %c\n", c); +} + +void my_put_next_rx_proto(void *callback_state,char *proto_bits){ + //fprintf(stdout, "proto chars: %.*s\n",2, proto_bits); +} + +/* Called when a packet has been received */ +void my_datarx(void *callback_state, unsigned char *packet, size_t size) { + //size_t i; + // + //fprintf(stdout, "data (%zd bytes): ", size); + //for (i = 0; i < size; i++) { + // fprintf(stdout, "0x%02x ", packet[i]); + //} + //fprintf(stdout, "\n"); +} + +/* Called when a new packet can be send */ +void my_datatx(void *callback_state, unsigned char *packet, size_t *size) { + /* This should not happen while receiving.. */ + fprintf(stderr, "datarx callback called, this should not happen!\n"); + *size = 0; +} + + +int main(int argc, char *argv[]) { + struct freedv *freedv; + struct my_callback_state my_cb_state; + int frame; + int nin, nout; + + //////// + PROFILE_VAR(prof_freedv_rx); + machdep_profile_init(); + + semihosting_init(); + + //////// + freedv = freedv_open(FREEDV_MODE_700D); + + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 0); + + short speech_out[freedv_get_n_speech_samples(freedv)]; + + freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state); + freedv_set_callback_protocol(freedv, &my_put_next_rx_proto, NULL, &my_cb_state); + freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); + + frame = 0; + + //////// + // Main loop + + nin = freedv_nin(freedv); + int in_ptr = 0; + while(in_ptr < api_demod_700d_in_10f_len) { + + PROFILE_SAMPLE(prof_freedv_rx); + + nout = freedv_shortrx(freedv, speech_out, (short *)&api_demod_700d_in_10f[in_ptr], 1.0f); + + PROFILE_SAMPLE_AND_LOG2(prof_freedv_rx, "freedv_rx"); + + //if (nout) write(f_out, speech_out, (sizeof(short) * nout)); + + frame++; + in_ptr += nin * 2; + } + + machdep_profile_print_logged_samples(); + + fclose(stdout); + fclose(stderr); + +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_api_mod.c b/stm32/unittest/src/tst_api_mod.c new file mode 100644 index 0000000..dc060a1 --- /dev/null +++ b/stm32/unittest/src/tst_api_mod.c @@ -0,0 +1,274 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_api_mod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: August 2014, Oct 2018 + + Test modem modulation via freedv API on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* Typical run, using internal testframes: + + # Copy N frames of a raw audio file to stm_in.raw. + # N=6, count = 6 * 1280 * 2 = 15360 + dd bs=1 count=15360 if=../../../../raw/hts1.raw of=stm_in.raw + + # Reference + freedv_tx 700D stm_in.raw ref_mod.raw --testframes + + # Create config + echo "71000000" > stm_cfg.txt + + # Run stm32 + run_stm32_prog ../../src/tst_api_mod.elf --load + + # Check output + freedv_rx 700D ref_mod.raw ref_rx.raw --testframes + freedv_rx 700D stm_out.raw stm_rx.raw --testframes + #optional: ofdm_demod ref_mod.raw ref_demod.raw --ldpc --testframes + #optional: ofdm_demod stm_out.raw stm_demod.raw --ldpc --testframes + + compare_ints -s -b 2 ref_mod.raw stm_out.raw +*/ + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> + +#include "freedv_api.h" +#include "codec2.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" +#include "memtools.h" + +struct my_callback_state { + char tx_str[80]; + char *ptx_str; + int calls; +}; + +char my_get_next_tx_char(void *callback_state) { + struct my_callback_state* pstate = (struct my_callback_state*)callback_state; + char c = *pstate->ptx_str++; + //fprintf(stderr, "my_get_next_tx_char: %c\n", c); + if (*pstate->ptx_str == 0) { + pstate->ptx_str = pstate->tx_str; + } + return c; +} + +void my_get_next_proto(void *callback_state,char *proto_bits){ + struct my_callback_state* cb_states = (struct my_callback_state*)(callback_state); + snprintf(proto_bits,3,"%2d",cb_states->calls); + cb_states->calls = cb_states->calls + 1; +} + +/* Called when a packet has been received */ +void my_datarx(void *callback_state, unsigned char *packet, size_t size) { + /* This should not happen while sending... */ + fprintf(stderr, "datarx callback called, this should not happen!\n"); +} + +/* Called when a new packet can be send */ +void my_datatx(void *callback_state, unsigned char *packet, size_t *size) { + static int data_toggle; + /* Data could come from a network interface, here we just make up some */ + data_toggle = !data_toggle; + if (data_toggle) { + /* Send a packet with data */ + int i; + for (i = 0; i < 64; i++) + packet[i] = i; + *size = i; + } else { + /* set size to zero, the freedv api will insert a header frame */ + *size = 0; + } +} + + +int main(int argc, char *argv[]) { + struct freedv *freedv; + int f_cfg, f_in, f_out; + int frame; + int num_read; + + //struct CODEC2 *c2; + struct my_callback_state my_cb_state; + + semihosting_init(); + memtools_find_unused(printf); + + //////// + // Test configuration, read from stm_cfg.txt + int config_mode; // 0 + int config_testframes; // 1 + int use_clip = 0; // 2 + int use_txbpf = 0; // 3 + //int config_verbose; // 6 + //int config_profile; // 7 + char config[8]; + f_cfg = open("stm_cfg.txt", O_RDONLY); + if (f_cfg == -1) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (read(f_cfg, &config[0], 8) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_mode = config[0] - '0'; + if (config_mode == 8) + { + // For the purposes of the UT system, '8' is 700E. + config_mode = FREEDV_MODE_700E; + } + config_testframes = config[1] - '0'; + use_clip = config[2] - '0'; + use_txbpf = config[3] - '0'; + //config_verbose = config[6] - '0'; + //config_profile = config[7] - '0'; + close(f_cfg); + + //int use_codectx = 0; + //int use_datatx = 0; + //int use_testframes = 0; + int use_ext_vco = 0; + + //////// + //PROFILE_VAR(freedv_start); + //machdep_profile_init(); + + //////// + freedv = freedv_open(config_mode); + assert(freedv != NULL); + + fprintf(stderr, "freedv opened %p\n", freedv); + + freedv_set_test_frames(freedv, config_testframes); + + int n_speech_samples = freedv_get_n_speech_samples(freedv); + short *speech_in = (short*)malloc(sizeof(short)*n_speech_samples); + int n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv); + short *mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples); + + fprintf(stderr, "n_speech_samples: %d n_nom_modem_samples: %d\n", + n_speech_samples, n_nom_modem_samples); + + fprintf(stderr, "mod_out: %p\n", mod_out); + + /* + // This is "codectx" operation: + int c2_mode; + if (config_mode == FREEDV_MODE_700) { + c2_mode = CODEC2_MODE_700; + } else if ((config_mode == FREEDV_MODE_700B) || + (config_mode == FREEDV_MODE_800XA)) { + c2_mode = CODEC2_MODE_700B; + } else if ((config_mode == FREEDV_MODE_700C) || + (config_mode == FREEDV_MODE_700D)) { + c2_mode = CODEC2_MODE_700C; + } else { + c2_mode = CODEC2_MODE_1300; + } + c2 = codec2_create(c2_mode); + + int bits_per_codec_frame = codec2_bits_per_frame(c2); + int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; + int codec_frames = freedv_get_n_codec_bits(freedv) / bits_per_codec_frame; + int inbuf_size = bytes_per_codec_frame * codec_frames; + unsigned char inbuf[inbuf_size]; +*/ + + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 1); + freedv_set_clip(freedv, use_clip); + freedv_set_tx_bpf(freedv, use_txbpf); + freedv_set_ext_vco(freedv, use_ext_vco); + freedv_set_eq(freedv, 1); + + memtools_find_unused(printf); + + // set up callback for txt msg chars + sprintf(my_cb_state.tx_str, "cq cq cq hello world\r"); + my_cb_state.ptx_str = my_cb_state.tx_str; + my_cb_state.calls = 0; + freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state); + + // set up callback for protocol bits + freedv_set_callback_protocol(freedv, NULL, &my_get_next_proto, &my_cb_state); + + // set up callback for data packets + freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); + + //////// + // Streams + f_in = open("stm_in.raw", O_RDONLY); + if (f_in == -1) { + perror("Error opening input file\n"); + exit(1); + } + + f_out = open("stm_out.raw", (O_CREAT | O_WRONLY), 0644); + if (f_out == -1) { + perror("Error opening output file\n"); + exit(1); + } + + frame = 0; + + fprintf(stderr, "starting main loop\n"); + + //////// + // Main loop + while ((num_read = read(f_in, speech_in, (sizeof(short) * n_speech_samples))) == + (sizeof(short) * n_speech_samples)) { + fprintf(stderr, "frame: %d\r", frame); + + freedv_tx(freedv, mod_out, speech_in); + + write(f_out, mod_out, (sizeof(short) * n_nom_modem_samples)); + + frame++ ; + //machdep_profile_print_logged_samples(); + + } + printf("Done\n"); + + close(f_in); + close(f_out); + printf("\nEnd of Test\n"); + + return(0); +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_api_mod_700d_profile.c b/stm32/unittest/src/tst_api_mod_700d_profile.c new file mode 100644 index 0000000..9c7f881 --- /dev/null +++ b/stm32/unittest/src/tst_api_mod_700d_profile.c @@ -0,0 +1,167 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_api_mod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: August 2014, Oct 2018 + + Test modem modulation via freedv API on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* This is a test implementation of the Freev API Modulation function. + * It is used for profiling performance. + * + * The input is generated within the test. + * The output is ignored. + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <math.h> +#include <assert.h> + +#include "freedv_api.h" +#include "codec2.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +struct my_callback_state { + char tx_str[80]; + char *ptx_str; + int calls; +}; + +char my_get_next_tx_char(void *callback_state) { + struct my_callback_state* pstate = (struct my_callback_state*)callback_state; + char c = *pstate->ptx_str++; + if (*pstate->ptx_str == 0) { + pstate->ptx_str = pstate->tx_str; + } + return c; +} + +void my_get_next_proto(void *callback_state,char *proto_bits){ + struct my_callback_state* cb_states = (struct my_callback_state*)(callback_state); + snprintf(proto_bits,3,"%2d",cb_states->calls); + cb_states->calls = cb_states->calls + 1; +} + +/* Called when a packet has been received */ +void my_datarx(void *callback_state, unsigned char *packet, size_t size) { + /* This should not happen while sending... */ + assert(0); +} + +/* Called when a new packet can be send */ +void my_datatx(void *callback_state, unsigned char *packet, size_t *size) { + static int data_toggle; + /* Data could come from a network interface, here we just make up some */ + data_toggle = !data_toggle; + if (data_toggle) { + /* Send a packet with data */ + int i; + for (i = 0; i < 64; i++) + packet[i] = i; + *size = i; + } else { + /* set size to zero, the freedv api will insert a header frame */ + *size = 0; + } +} + + +int main(int argc, char *argv[]) { + struct freedv *freedv; + int i; + + struct my_callback_state my_cb_state; + + int use_clip = 0; + int use_txbpf = 0; + int use_ext_vco = 0; + + //////// + PROFILE_VAR(prof_freedv_tx); + machdep_profile_init(); + + semihosting_init(); + + //////// + freedv = freedv_open(FREEDV_MODE_700D); + + int n_speech_samples = freedv_get_n_speech_samples(freedv); + short *speech_in = (short*)malloc(sizeof(short)*n_speech_samples); + int n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv); + short *mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples); + + freedv_set_snr_squelch_thresh(freedv, -100.0); + freedv_set_squelch_en(freedv, 1); + freedv_set_clip(freedv, use_clip); + freedv_set_tx_bpf(freedv, use_txbpf); + freedv_set_ext_vco(freedv, use_ext_vco); + + // set up callback for txt msg chars + sprintf(my_cb_state.tx_str, "cq cq cq hello world\r"); + my_cb_state.ptx_str = my_cb_state.tx_str; + my_cb_state.calls = 0; + freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state); + + // set up callback for protocol bits + freedv_set_callback_protocol(freedv, NULL, &my_get_next_proto, &my_cb_state); + + // set up callback for data packets + freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); + + int frame = 0; + + for (i=0; i<n_speech_samples; i++) speech_in[i] = 0; + + //////// + // Main loop + while(frame < 10) { + + PROFILE_SAMPLE(prof_freedv_tx); + + freedv_tx(freedv, mod_out, speech_in); + + PROFILE_SAMPLE_AND_LOG2(prof_freedv_tx, "freedv_tx"); + + //write(f_out, mod_out, (sizeof(short) * n_nom_modem_samples)); + + frame++ ; + + } + + machdep_profile_print_logged_samples(); + + fclose(stdout); + fclose(stderr); + return(0); +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_api_tx.c b/stm32/unittest/src/tst_api_tx.c new file mode 100644 index 0000000..00d4948 --- /dev/null +++ b/stm32/unittest/src/tst_api_tx.c @@ -0,0 +1,94 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: freedv_tx_profile.c + AUTHOR......: David Rowe + DATE CREATED: 13 August 2014 + + Profiling freedv_tx() operation on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <math.h> +#include <errno.h> + +#include "semihosting.h" +#include "codec2_ofdm.h" +#include "ofdm_internal.h" +#include "interldpc.h" +#include "gp_interleaver.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "freedv_api.h" +#include "machdep.h" + +int main(int argc, char *argv[]) { + struct freedv *f; + FILE *fin, *fout; + int frame, n_samples; + + semihosting_init(); + + //PROFILE_VAR(freedv_start); + + //machdep_profile_init(); + + f = freedv_open(FREEDV_MODE_1600); + n_samples = freedv_get_n_speech_samples(f); + short inbuf[n_samples], outbuf[n_samples]; + + freedv_set_test_frames(f, 1); + + // Transmit --------------------------------------------------------------------- + + fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + printf("Error opening input file\n"); + exit(1); + } + + fout = fopen("mod.raw", "wb"); + if (fout == NULL) { + printf("Error opening output file\n"); + exit(1); + } + + frame = 0; + + while (fread(inbuf, sizeof(short), n_samples, fin) == n_samples) { + //PROFILE_SAMPLE(freedv_start); + freedv_tx(f, outbuf, inbuf); + //PROFILE_SAMPLE_AND_LOG2(freedv_start, " freedv_tx"); + + fwrite(outbuf, sizeof(short), n_samples, fout); + printf("frame: %d\n", ++frame); + //machdep_profile_print_logged_samples(); + } + + fclose(fin); + fclose(fout); + + return 0; +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_codec2_dec.c b/stm32/unittest/src/tst_codec2_dec.c new file mode 100644 index 0000000..406a84d --- /dev/null +++ b/stm32/unittest/src/tst_codec2_dec.c @@ -0,0 +1,164 @@ +/*------------------------------------------------------ + + FILE........: tst_codec2_dec.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 30 May 2013, Oct 2018 + + Test Codec 2 decoding on the STM32F4. + +-------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* Typical run, using internal testframes: + + # Input + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw + c2enc 700C spch_in.raw stm_in.raw + + # Reference + c2dec 700C stm_in.raw ref_dec.raw + + # Create config + echo "81000000" > stm_cfg.txt + + # Run stm32 + run_stm32_prog ../../src/tst_codec2_dec.elf --load + + # Compare outputs + compare_ints -s -b 2 ref_dec.raw stm_out.raw + + # Manual play (and listen) + aplay -f S16_LE ref_dec.raw + # + aplay -f S16_LE stm_out.raw + + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> +#include <assert.h> + +#include "codec2.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + + +static char fin_buffer[1024]; +static __attribute__ ((section (".ccm"))) char fout_buffer[4*8192]; + +int main(int argc, char *argv[]) { + int f_cfg; + int frame; + void *codec2; + short *buf; + unsigned char *bits; + + int nsam, nbit, nbyte; + + semihosting_init(); + + //////// + // Test configuration, read from stm_cfg.txt + int config_mode; // 0 + int config_gray; // 1 + //int config_verbose; // 6 + //int config_profile; // 7 + char config[8]; + f_cfg = open("stm_cfg.txt", O_RDONLY); + if (f_cfg == -1) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (read(f_cfg, &config[0], 8) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_mode = config[0] - '0'; + config_gray = config[1] - '0'; + //config_verbose = config[6] - '0'; + //config_profile = config[7] - '0'; + close(f_cfg); + + + //////// + // Setup + codec2 = codec2_create(config_mode); + assert(codec2 != NULL); + codec2_set_natural_or_gray(codec2, config_gray); + + nsam = codec2_samples_per_frame(codec2); + nbit = codec2_bits_per_frame(codec2); + buf = (short*)malloc(nsam*sizeof(short)); + nbyte = (nbit + 7) / 8; + bits = (unsigned char*)malloc(nbyte*sizeof(char)); + + + //////// + // Streams + FILE* fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + perror("Error opening input file\n"); + exit(1); + } + setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer)); + + FILE *fout = fopen("stm_out.raw", "wb" ); + if (fout == NULL) { + perror("Error opening output file\n"); + exit(1); + } + setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer)); + + frame = 0; + + //////// + // Main loop + int bytes_per_frame = (sizeof(char) * nbyte); + while (fread(bits, 1, bytes_per_frame, fin) == (size_t)bytes_per_frame) { + + codec2_decode_ber(codec2, buf, bits, 0.0); + + fwrite(buf, sizeof(short) , nsam, fout); + + frame ++; + } + + + fclose(fin); + fclose(fout); + + printf("\nEnd of Test\n"); + fclose(stdout); + fclose(stderr); + +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_codec2_enc.c b/stm32/unittest/src/tst_codec2_enc.c new file mode 100644 index 0000000..f799265 --- /dev/null +++ b/stm32/unittest/src/tst_codec2_enc.c @@ -0,0 +1,172 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_codec2_enc.c, (derived from codec2_profile.c) + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 30 May 2013, Oct 2018 + + Test Codec 2 encoding on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* This is a unit test implementation of the Codec2_encode function. + * + * Typical run: + + # Copy N frames of a raw audio file to stm_in.raw. + dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw + + # Run x86 command for reference output + c2enc 700C stm_in.raw ref_enc.raw + + # Create config + echo "80000000" > stm_cfg.txt + + # Run stm32 + run_stm32_prog ../../src/tst_codec2_enc.elf --load + + # Compare outputs + comare_ints -b 1 ref_enc.raw stm_out.raw + + # Manual play (and listen) + c2dec 700C ref_enc.raw ref_dec.raw + aplay -f S16_LE ref_out.raw + # + c2dec 700C stm_out.raw stm_dec.raw + aplay -f S16_LE stm_dec.raw + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include "codec2.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "semihosting.h" +#include "machdep.h" + +static __attribute__ ((section (".ccm"))) char fin_buffer[8*8192]; +char fout_buffer[1024]; + + +int main(int argc, char *argv[]) { + int f_cfg; + + struct CODEC2 *codec2; + short *buf; + unsigned char *bits; + int nsam, nbit, nbyte; + int gray; + int frame; + + //////// + // Semihosting + semihosting_init(); + + //////// + // Test configuration, read from stm_cfg.txt + int config_mode; // 0 + //int config_verbose; // 6 + //int config_profile; // 7 + char config[8]; + f_cfg = open("stm_cfg.txt", O_RDONLY); + if (f_cfg == -1) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (read(f_cfg, &config[0], 8) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_mode = config[0] - '0'; + //config_verbose = config[6] - '0'; + //config_profile = config[7] - '0'; + close(f_cfg); + + //////// + //PROFILE_VAR(freedv_start); + //machdep_profile_init(); + + //////// + codec2 = codec2_create(config_mode); + nsam = codec2_samples_per_frame(codec2); + nbit = codec2_bits_per_frame(codec2); + buf = (short*)malloc(nsam*sizeof(short)); + nbyte = (nbit + 7) / 8; + bits = (unsigned char*)malloc(nbyte*sizeof(char)); + + gray = 1; + //softdec = 0; + //bitperchar = 0; + + codec2_set_natural_or_gray(codec2, gray); + + //////// + // Streams + FILE* fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + perror("Error opening input file\n"); + exit(1); + } + setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer)); + + FILE* fout = fopen("stm_out.raw", "wb"); + if (fout == NULL) { + perror("Error opening output file\n"); + exit(1); + } + + frame = 0; + + int bytes_per_frame = (sizeof(short) * nsam); + while (fread(buf,1, bytes_per_frame, fin) == bytes_per_frame) { + + //PROFILE_SAMPLE(enc_start); + codec2_encode(codec2, bits, buf); + //PROFILE_SAMPLE_AND_LOG2(, enc_start, " enc"); + + fwrite(bits, 1, (sizeof(char) * nbyte), fout); + printf("frame: %d\n", ++frame); + + //machdep_profile_print_logged_samples(); + } + + codec2_destroy(codec2); + + free(buf); + free(bits); + fclose(fin); + fclose(fout); + + printf("\nEnd of Test\n"); + fclose(stdout); + fclose(stderr); + + return(0); +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_codec2_fft_init.c b/stm32/unittest/src/tst_codec2_fft_init.c new file mode 100644 index 0000000..aae5f60 --- /dev/null +++ b/stm32/unittest/src/tst_codec2_fft_init.c @@ -0,0 +1,104 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_codec2_fft_init.c, + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 30 May 2013, Oct 2018, Feb 2018 + + Test FFT Window initialization in Codec2_create + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <math.h> + +#include "codec2.h" +#include "codec2_internal.h" +#include "defines.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "semihosting.h" +#include "machdep.h" + +static const float expect_w[] = { + 0.004293, 0.004301, 0.004309, 0.004315, + 0.004320, 0.004323, 0.004326, 0.004328, + 0.004328, 0.004328, 0.004326, 0.004323, + 0.004320, 0.004315, 0.004309, 0.004301}; + + +static const float expect_W[] = { + -0.002176, 0.002195, 0.004429, -0.008645, + -0.012196, 0.065359, 0.262390, 0.495616, + 0.601647, 0.495616, 0.262390, 0.065359, + -0.012196, -0.008645, 0.004429, 0.002195}; + + +int float_cmp(float a, float b) { + if ( fabsf(a - b) < 1e-6f ) return 1; + else return 0; + } + +int main(int argc, char *argv[]) { + + struct CODEC2 *codec2; + int i, j; + + //////// + // Semihosting + semihosting_init(); + + //////// + codec2 = codec2_create(CODEC2_MODE_700C); + + j = (codec2->c2const.m_pitch / 2) - 8; + for (i=0; i<16; i++) { + printf("w[%d] = %f", j+i, + (double)codec2->w[j+i]); + if (!float_cmp(codec2->w[j+i], expect_w[i])) { + printf(" Error, expected %f", (double)expect_w[i]); + } + printf("\n"); + } + + printf("\n"); + + j = (FFT_ENC / 2) - 8; + for (i=0; i<16; i++) { + printf("W[%d] = %f", j+i, + (double)codec2->W[j+i]); + if (!float_cmp(codec2->W[j+i], expect_W[i])) { + printf(" Error, expected %f", (double)expect_W[i]); + } + printf("\n"); + } + + codec2_destroy(codec2); + + printf("\nEnd of Test\n"); + fclose(stdout); + fclose(stderr); + + return(0); +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_ldpc_dec.c b/stm32/unittest/src/tst_ldpc_dec.c new file mode 100644 index 0000000..f177255 --- /dev/null +++ b/stm32/unittest/src/tst_ldpc_dec.c @@ -0,0 +1,204 @@ +/* + FILE...: ldpc_dec.c + AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe, Don Reid + CREATED: Sep 2016 + + Command line C LDPC decoder derived from MpDecode.c in the CML + library. Allows us to run the same decoder in Octave and C. The + code is defined by the parameters and array stored in the include + file below, which can be machine generated from the Octave function + ldpc_fsk_lib.m:ldpc_decode() + + The include file also contains test input/output vectors for the LDPC + decoder for testing this program. If no input file "stm_in.raw" is found + then the built in test mode will run. + + If there is an input is should be encoded data from the x86 ldpc_enc + program. Here is the suggested way to run: + + ldpc_enc /dev/zero stm_in.raw --sd --code HRA_112_112 --testframes 6 + + ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes + + <Load stm32 and run> + + cmp -l ref_out.raw stm_out.raw + << Check BER values in logs >> +*/ + +#include <assert.h> +#include <errno.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "mpdecode_core.h" +#include "ofdm_internal.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +/* generated by ldpc_fsk_lib.m:ldpc_decode() */ +/* Machine generated consts, H_rows, H_cols, test input/output data to + change LDPC code regenerate this file. */ + +#include "HRA_112_112.h" + +int testframes = 1; + +static char fin_buffer[1024]; +static __attribute__ ((section (".ccm"))) char fout_buffer[8*8192]; + +int main(int argc, char *argv[]) { + int CodeLength, NumberParityBits; + int i, parityCheckCount; + uint8_t out_data[HRA_112_112_CODELENGTH]; + struct LDPC ldpc; + int data_bits_per_frame; + FILE *fout; + int iter, total_iters; + int Tbits, Terrs, Tbits_raw, Terrs_raw; + + int nread, frame; + + semihosting_init(); + + fprintf(stderr, "LDPC decode test and profile\n"); + + PROFILE_VAR(ldpc_decode); + machdep_profile_init(); + + ldpc.max_iter = HRA_112_112_MAX_ITER; + ldpc.dec_type = 0; + ldpc.q_scale_factor = 1; + ldpc.r_scale_factor = 1; + ldpc.CodeLength = HRA_112_112_CODELENGTH; + ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS; + ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS; + ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT; + ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT; + ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows; + ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols; + + CodeLength = ldpc.CodeLength; + NumberParityBits = ldpc.NumberParityBits; + data_bits_per_frame = ldpc.NumberRowsHcols; + unsigned char ibits[data_bits_per_frame]; + unsigned char pbits[NumberParityBits]; + +// // Allocate common space which can be shared with other functions. +// int size_common; +// uint8_t *common_array; + +// ldpc_init(&ldpc, &size_common); +// fprintf(stderr, "ldpc needs %d bytes of shared memory\n", size_common); +// common_array = malloc(size_common); + + testframes = 1; + total_iters = 0; + + if (testframes) { + uint16_t r[data_bits_per_frame]; + ofdm_rand(r, data_bits_per_frame); + + for(i=0; i<data_bits_per_frame; i++) { + ibits[i] = r[i] > 16384; + } + encode(&ldpc, ibits, pbits); + Tbits = Terrs = Tbits_raw = Terrs_raw = 0; + } + + FILE* fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + fprintf(stderr, "Error opening input file\n"); + fflush(stderr); + exit(1); + } + setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer)); + + fout = fopen("stm_out.raw", "wb"); + if (fout == NULL) { + fprintf(stderr, "Error opening output file\n"); + fflush(stderr); + exit(1); + } + setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer)); + + float *input_float = calloc(CodeLength, sizeof(float)); + + nread = CodeLength; + fprintf(stderr, "CodeLength: %d\n", CodeLength); + + frame = 0; + while(fread(input_float, sizeof(float) , nread, fin) == nread) { + fprintf(stderr, "frame %d\n", frame); + + if (testframes) { + char in_char; + for (i=0; i<data_bits_per_frame; i++) { + in_char = input_float[i] < 0; + if (in_char != ibits[i]) { + Terrs_raw++; + } + Tbits_raw++; + } + for (i=0; i<NumberParityBits; i++) { + in_char = input_float[i+data_bits_per_frame] < 0; + if (in_char != pbits[i]) { + Terrs_raw++; + } + Tbits_raw++; + } + } + float llr[CodeLength]; + sd_to_llr(llr, input_float, CodeLength); + + PROFILE_SAMPLE(ldpc_decode); + iter = run_ldpc_decoder(&ldpc, out_data, llr, &parityCheckCount); + PROFILE_SAMPLE_AND_LOG2(ldpc_decode, "ldpc_decode"); + //fprintf(stderr, "iter: %d\n", iter); + total_iters += iter; + + fwrite(out_data, sizeof(char), data_bits_per_frame, fout); + + if (testframes) { + for (i=0; i<data_bits_per_frame; i++) { + if (out_data[i] != ibits[i]) { + Terrs++; + //fprintf(stderr, "%d %d %d\n", i, out_data[i], ibits[i]); + } + Tbits++; + } + } + + frame++; + } + + fclose(fin); + fclose(fout); + + fprintf(stderr, "total iters %d\n", total_iters); + + if (testframes) { + fprintf(stderr, "Raw Tbits..: %d Terr: %d BER: %4.3f\n", + Tbits_raw, Terrs_raw, (double)(Terrs_raw/(Tbits_raw+1E-12))); + fprintf(stderr, "Coded Tbits: %d Terr: %d BER: %4.3f\n", + Tbits, Terrs, (double)(Terrs/(Tbits+1E-12))); + } + + printf("\nStart Profile Data\n"); + machdep_profile_print_logged_samples(); + printf("End Profile Data\n"); + + fclose(stdout); + fclose(stderr); + + return 0; +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_ldpc_enc.c b/stm32/unittest/src/tst_ldpc_enc.c new file mode 100644 index 0000000..30624d2 --- /dev/null +++ b/stm32/unittest/src/tst_ldpc_enc.c @@ -0,0 +1,114 @@ +/* + FILE...: ldpc_enc.c + AUTHOR.: Bill Cowley, David Rowe + CREATED: Sep 2016 + + STM32 Version: Aug 2018 - Don Reid +*/ + +/* This is a unit test implementation of the LDPC encode function. + * + * Typical run: + + ofdm_gen_test_bits stm_in.raw 6 --rand --ldpc + + ldpc_enc stm_in.raw ref_out.raw --code HRA_112_112 + + <Load stm32 and run> + + cmp -l ref_out.raw stm_out.raw + + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "mpdecode_core.h" + +#include "semihosting.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +/* generated by ldpc_fsk_lib.m:ldpc_decode() */ + +#include "HRA_112_112.h" + +static __attribute__ ((section (".ccm"))) char fin_buffer[8*8192]; +char fout_buffer[1024]; + +int opt_exists(char *argv[], int argc, char opt[]) { + int i; + for (i=0; i<argc; i++) { + if (strcmp(argv[i], opt) == 0) { + return i; + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned char ibits[HRA_112_112_NUMBERROWSHCOLS]; + unsigned char pbits[HRA_112_112_NUMBERPARITYBITS]; + struct LDPC ldpc; + + semihosting_init(); + + printf("LDPC encode test and profile\n"); + + PROFILE_VAR(ldpc_encode); + + machdep_profile_init(); + + /* set up LDPC code from include file constants */ + /* short rate 1/2 code for FreeDV HF digital voice */ + ldpc.CodeLength = HRA_112_112_CODELENGTH; + ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS; + ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS; + ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT; + ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT; + ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows; + ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols; + + FILE* fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + printf("Error opening input file\n"); + exit(1); + } + setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer)); + + FILE* fout = fopen("stm_out.raw", "wb"); + if (fout == NULL) { + printf("Error opening output file\n"); + exit(1); + } + + while (fread(ibits, sizeof(char) , ldpc.NumberParityBits, fin) == + ldpc.NumberParityBits) { + + PROFILE_SAMPLE(ldpc_encode); + encode(&ldpc, ibits, pbits); + PROFILE_SAMPLE_AND_LOG2(ldpc_encode, " ldpc_encode"); + + fwrite(ibits, sizeof(char) , ldpc.NumberRowsHcols, fout); + fwrite(pbits, sizeof(char) , ldpc.NumberParityBits, fout); + } + + fclose(fin); + fclose(fout); + + fflush(stdout); + stdout = freopen("stm_profile", "w", stdout); + machdep_profile_print_logged_samples(); + + fclose(stdout); + fclose(stderr); + + return 0; +} diff --git a/stm32/unittest/src/tst_ofdm_demod.c b/stm32/unittest/src/tst_ofdm_demod.c new file mode 100644 index 0000000..54cc027 --- /dev/null +++ b/stm32/unittest/src/tst_ofdm_demod.c @@ -0,0 +1,438 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_ofdm_demod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 7 July 2018 + + Test and profile OFDM de-modulation on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + + +/* This is a unit test implementation of the OFDM Demod function. + * It is used for several tests: + * + * tst_ofdm_demod_ideal Simple 10 frames with no degradation. + * tst_ofdm_demod_AWGN Just AWGN in channel. + * tst_ofdm_demod_fade AWGN and fading in channel. + * tst_ofdm_demod_profile Profile, disable verbose logging. + * + * See tst_ofdm_demod_setup and tst_ofdm_demod_check scripts for details. + * + * This program reads a file "stm_cfg.txt" at startup to configure its options. + * + * This program is intended to be run using input data, typically + * Codec2 frames, which may have had simulated RF degradation applied. + * For example: + * + * ofdm_get_test_bits - 10 | * ofdm_mod - - | \ + * cohpsk_ch - stm_in.raw -20 -Fs 8000 -f -5 + * + * Reference data can be created by running the same input through the x86 + * ofdm_demod tool. + * + * ofdm_demod stm_in.raw ref_demod_out.raw -o ofdm_demod_ref_log.txt --testframes + * + * Comparison of the results to the reference will depend on the test conditions. + * Some small differences are expected due to differences in implementation. + * + */ + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "semihosting.h" +#include "codec2_ofdm.h" +#include "ofdm_internal.h" +#include "mpdecode_core.h" +#include "ldpc_codes.h" +#include "interldpc.h" +#include "gp_interleaver.h" +#include "test_bits_ofdm.h" + +#include "debug_alloc.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +#define NDISCARD 20 + +extern const uint8_t payload_data_bits[]; +extern const int test_bits_ofdm[]; + +static struct OFDM_CONFIG *ofdm_config; + +static int ofdm_bitsperframe; +static int ofdm_rowsperframe; +static int ofdm_nuwbits; +static int ofdm_ntxtbits; +static int ofdm_nin; +static char fout_buffer[4*4096]; +static __attribute__ ((section (".ccm"))) char fdiag_buffer[4*8192]; +static __attribute__ ((section (".ccm"))) char fin_buffer[4096*8]; + +static char *statemode[] = { + "search", + "trial", + "synced" +}; + +static FILE *fout, *fdiag; +void flush_all(void) { + fflush(fout); + fflush(fdiag); + fflush(stdout); + fflush(stderr); + } + +int main(int argc, char *argv[]) { + struct OFDM *ofdm; + FILE *fcfg; + int nin_frame; + struct LDPC ldpc; + + // Test configuration, read from stm_cfg.txt + int config_verbose; + int config_testframes; + int config_ldpc_en; + int config_log_payload_syms; + int config_profile; + + int i; + int Nerrs, Terrs, Tbits, Terrs2, Tbits2, frame_count; + int Tbits_coded, Terrs_coded; + + semihosting_init(); + + fprintf(stdout, "OFDM Demod test\n"); + + // Read configuration - a file of '0' or '1' characters + char config[8]; + fcfg = fopen("stm_cfg.txt", "r"); + if (fcfg == NULL) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (fread(&config[0], 1, 8, fcfg) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_verbose = config[0] - '0'; + config_testframes = config[1] - '0'; + config_ldpc_en = config[2] - '0'; + config_log_payload_syms = config[3] - '0'; + config_profile = config[4] - '0'; + fclose(fcfg); + + int Nerrs_raw = 0; + int Nerrs_coded = 0; + int iter = 0; + int parityCheckCount = 0; + + PROFILE_VAR(ofdm_demod_start, ofdm_demod_sync_search, + ofdm_demod_demod, ofdm_demod_diss, ofdm_demod_snr); + ofdm_demod_start = 0; + ofdm_demod_sync_search = 0; + ofdm_demod_demod = 0; + ofdm_demod_diss = 0; + ofdm_demod_snr = 0; + if (config_profile) machdep_profile_init(); + + ofdm = ofdm_create(NULL); + assert(ofdm != NULL); + + /* Get a copy of the actual modem config */ + ofdm_config = ofdm_get_config_param(ofdm); + + ldpc_codes_setup(&ldpc, "HRA_112_112"); + + ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm); + ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps); + ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits; + ofdm_ntxtbits = ofdm_config->txtbits; + ofdm_nin = ofdm_get_nin(ofdm); + + ofdm_set_verbose(ofdm, config_verbose); + + int Nmaxsamperframe = ofdm_get_max_samples_per_frame(ofdm); + + int data_bits_per_frame = ldpc.data_bits_per_frame; + int coded_bits_per_frame = ldpc.coded_bits_per_frame; + int coded_syms_per_frame = ldpc.coded_bits_per_frame/ofdm->bps; + + short rx_scaled[Nmaxsamperframe]; + int rx_bits[ofdm_bitsperframe]; + char rx_bits_char[ofdm_bitsperframe]; + uint8_t rx_uw[ofdm_nuwbits]; + short txt_bits[ofdm_ntxtbits]; + int f = 0; + Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = 0; + + float snr_est_smoothed_dB = 0.0; + + float EsNo = 3.0f; // Constant from ofdm_demod.c + + COMP payload_syms[coded_syms_per_frame]; + float payload_amps[coded_syms_per_frame]; + COMP codeword_symbols[coded_syms_per_frame]; + float codeword_amps[coded_syms_per_frame]; + + FILE* fin = fopen("stm_in.raw", "rb"); + if (fin == NULL) { + fprintf(stderr, "Error opening input file\n"); + exit(1); + } + setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer)); + + + fout = fopen("stm_out.raw", "wb"); + if (fout == NULL) { + fprintf(stderr, "Error opening output file\n"); + exit(1); + } + setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer)); + + fdiag = fopen("stm_diag.raw", "wb"); + if (fdiag == NULL) { + fprintf(stderr, "Error opening diag file\n"); + exit(1); + } + setvbuf(fdiag, fdiag_buffer,_IOFBF,sizeof(fdiag_buffer)); + + nin_frame = ofdm_get_nin(ofdm); + int num_read; + + while((num_read = fread(rx_scaled, sizeof(short) , nin_frame, fin)) == nin_frame) { + + int log_payload_syms_flag = 0; + + if (config_profile) PROFILE_SAMPLE(ofdm_demod_start); + + /* demod */ + + if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_start, " ofdm_demod_start"); + + if (ofdm->sync_state == search) { + if (config_profile) PROFILE_SAMPLE(ofdm_demod_sync_search); + ofdm_sync_search_shorts(ofdm, rx_scaled, (OFDM_PEAK/2)); + if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_sync_search, " ofdm_demod_sync_search"); + } + + if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial) ) { + if (config_profile) PROFILE_SAMPLE(ofdm_demod_demod); + ofdm_demod_shorts(ofdm, rx_bits, rx_scaled, (OFDM_PEAK/2)); + if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_demod, " ofdm_demod_demod"); + if (config_profile) PROFILE_SAMPLE(ofdm_demod_diss); + ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw); + ofdm_disassemble_qpsk_modem_packet(ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits); + if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_diss, " ofdm_demod_diss"); + log_payload_syms_flag = 1; + + /* SNR estimation and smoothing */ + if (config_profile) PROFILE_SAMPLE(ofdm_demod_snr); + float EsNodB = ofdm_esno_est_calc((complex float*)payload_syms, coded_syms_per_frame); + float snr_est_dB = ofdm_snr_from_esno(ofdm, EsNodB); + snr_est_smoothed_dB = 0.9f * snr_est_smoothed_dB + 0.1f *snr_est_dB; + if (config_profile) { + PROFILE_SAMPLE_AND_LOG2(ofdm_demod_snr, " ofdm_demod_snr"); + } + + // LDPC + if (config_ldpc_en) { // was llr_en in orig + + /* first few symbols are used for UW and txt bits, find + start of (224,112) LDPC codeword and extract QPSK + symbols and amplitude estimates */ + assert((ofdm_nuwbits + ofdm_ntxtbits + coded_bits_per_frame) + == ofdm_bitsperframe); + + /* newest symbols at end of buffer (uses final i from last loop) */ + for(i=0; i < coded_syms_per_frame; i++) { + codeword_symbols[i] = payload_syms[i]; + codeword_amps[i] = payload_amps[i]; + } + + /* run de-interleaver */ + COMP codeword_symbols_de[coded_syms_per_frame]; + float codeword_amps_de[coded_syms_per_frame]; + + gp_deinterleave_comp (codeword_symbols_de, codeword_symbols, coded_syms_per_frame); + gp_deinterleave_float(codeword_amps_de, codeword_amps, coded_syms_per_frame); + + float llr[coded_bits_per_frame]; + + if (config_ldpc_en) { + uint8_t out_char[coded_bits_per_frame]; + + if (config_testframes) { + Terrs += count_uncoded_errors(&ldpc, ofdm_config, codeword_symbols_de, 0); + Tbits += coded_bits_per_frame; + } + + symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, + EsNo, ofdm->mean_amp, coded_syms_per_frame); + iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount); + + //fprintf(stderr,"iter: %d pcc: %d\n", iter, parityCheckCount); + + if (config_testframes) { + /* construct payload data bits */ + uint8_t payload_data_bits[data_bits_per_frame]; + ofdm_generate_payload_data_bits(payload_data_bits, data_bits_per_frame); + + Nerrs_coded = count_errors(payload_data_bits, out_char, data_bits_per_frame); + Terrs_coded += Nerrs_coded; + Tbits_coded += data_bits_per_frame; + } + + fwrite(out_char, sizeof(char), data_bits_per_frame, fout); + } else { + /* lpdc_en == 0, external LDPC decoder, so output LLRs */ + symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, ofdm->mean_amp, coded_syms_per_frame); + fwrite(llr, sizeof(double), coded_bits_per_frame, fout); + } + } else { // !llrs_en (or ldpc_en) + + /* simple hard decision output for uncoded testing, excluding UW and txt */ + assert(coded_syms_per_frame*ofdm_config->bps == coded_bits_per_frame); + for (i = 0; i < coded_syms_per_frame; i++) { + int bits[2]; + complex float s = payload_syms[i].real + I * payload_syms[i].imag; + qpsk_demod(s, bits); + rx_bits_char[ofdm_config->bps * i] = bits[1]; + rx_bits_char[ofdm_config->bps * i + 1] = bits[0]; + } + + fwrite(rx_bits_char, sizeof (uint8_t), coded_bits_per_frame, fout); + } + + /* optional error counting on uncoded data in non-LDPC testframe mode */ + + if (config_testframes && (config_ldpc_en == 0)) { + /* build up a test frame consisting of unique word, txt bits, and psuedo-random + uncoded payload bits. The psuedo-random generator is the same as Octave so + it can interoperate with ofdm_tx.m/ofdm_rx.m */ + + int Npayloadbits = ofdm_bitsperframe-(ofdm_nuwbits+ofdm_ntxtbits); + uint16_t r[Npayloadbits]; + uint8_t payload_bits[Npayloadbits]; + uint8_t tx_bits[Npayloadbits]; + + ofdm_rand(r, Npayloadbits); + + for(i=0; i<Npayloadbits; i++) { + payload_bits[i] = r[i] > 16384; + //fprintf(stderr,"%d %d ", r[i], tx_bits_char[i]); + } + + uint8_t txt_bits[ofdm_ntxtbits]; + + for(i=0; i<ofdm_ntxtbits; i++) { + txt_bits[i] = 0; + } + + ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits); + + Nerrs = 0; + for(i=0; i<ofdm_bitsperframe; i++) { + if (tx_bits[i] != rx_bits[i]) { + Nerrs++; + } + } + + Terrs += Nerrs; + Tbits += ofdm_bitsperframe; + + if (frame_count >= NDISCARD) { + Terrs2 += Nerrs; + Tbits2 += ofdm_bitsperframe; + } + } // config_testframes ... + + frame_count++; + } // state "synced" or "trial" + + nin_frame = ofdm_get_nin(ofdm); + ofdm_sync_state_machine(ofdm, rx_uw); + + /* act on any events returned by state machine */ + + if (ofdm->sync_start) { + Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = Nerrs_raw = Nerrs_coded = 0; + } + + if (config_testframes && config_verbose) { + fprintf(stderr, "%3d st: %-6s", f, statemode[ofdm->last_sync_state]); + fprintf(stderr, " euw: %2d %1d f: %5.1f eraw: %3d ecdd: %3d iter: %3d pcc: %3d\n", + ofdm->uw_errors, ofdm->sync_counter, + (double)ofdm->foff_est_hz, + Nerrs, Nerrs_coded, iter, parityCheckCount); + } + + if (config_log_payload_syms) { + if (! log_payload_syms_flag) { + memset(payload_syms, 0, (sizeof(COMP)*coded_syms_per_frame)); + memset(payload_amps, 0, (sizeof(float)*coded_syms_per_frame)); + } + fwrite(payload_syms, sizeof(COMP), coded_syms_per_frame, fdiag); + fwrite(payload_amps, sizeof(float), coded_syms_per_frame, fdiag); + } + + f++; + } // while(fread(.., fin)) + + flush_all(); // To make sure this function is included in binary. + fclose(fin); + fclose(fout); + fclose(fdiag); + + if (config_testframes) { + printf("BER......: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs/Tbits, Tbits, Terrs); + if (!config_ldpc_en) { + printf("BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs2/Tbits2, Tbits2, Terrs2); + } + if (config_ldpc_en) { + printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n", + (double)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded); + } + } + + if (config_profile) { + printf("\nStart Profile Data\n"); + machdep_profile_print_logged_samples(); + printf("End Profile Data\n"); + } + + printf("\nEnd of Test\n"); + fclose(stdout); + fclose(stderr); + + return 0; +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_ofdm_mod.c b/stm32/unittest/src/tst_ofdm_mod.c new file mode 100644 index 0000000..77b2e37 --- /dev/null +++ b/stm32/unittest/src/tst_ofdm_mod.c @@ -0,0 +1,248 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tst_ofdm_mod.c + AUTHOR......: David Rowe, Don Reid + DATE CREATED: 25 June 2018 + + Test and profile OFDM modulation on the STM32F4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* This is a unit test implementation of the OFDM Mod function. + * + * Typical run: + + ofdm_gen_test_bits stm_in.raw 6 --rand + + ofdm_mod stm_in.raw ref_mod_out.raw + + echo "00000000" > stm_cfg.txt + + <Load stm32 and run> + + compare_ints -s -b2 ref_mod_out.raw mod.raw + + ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --testframes + ofdm_demod mod.raw stm_demod.raw --testframes + + * For LDPC use: + + ofdm_gen_test_bits stm_in.raw 6 --rand --ldpc + + ofdm_mod stm_in.raw ref_mod_out.raw --ldpc + + echo "00100000" > stm_cfg.txt + + <Load stm32 and run> + + ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --ldpc --testframes + ofdm_demod mod.raw stm_demod.raw --ldpc --testframes + + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "semihosting.h" +#include "codec2_ofdm.h" +#include "ofdm_internal.h" +#include "ldpc_codes.h" +#include "interldpc.h" +#include "gp_interleaver.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +#include "debug_alloc.h" + +int main(int argc, char *argv[]) { + struct OFDM *ofdm; + FILE *fcfg; + struct LDPC ldpc; + + // Test configuration, read from stm_cfg.txt + int config_verbose; +// int config_testframes; + int config_ldpc_en; +// int config_log_payload_syms; + int config_profile; + + int Nbitsperframe, Nsamperframe; + int frame = 0; + int i; + + semihosting_init(); + + printf("OFDM_mod test and profile\n"); + + // Read configuration - a file of '0' or '1' characters + char config[8]; + fcfg = fopen("stm_cfg.txt", "r"); + if (fcfg == NULL) { + fprintf(stderr, "Error opening config file\n"); + exit(1); + } + if (fread(&config[0], 1, 8, fcfg) != 8) { + fprintf(stderr, "Error reading config file\n"); + exit(1); + } + config_verbose = config[0] - '0'; +// config_testframes = config[1] - '0'; + config_ldpc_en = config[2] - '0'; +// config_log_payload_syms = config[3] - '0'; + config_profile = config[4] - '0'; + fclose(fcfg); + + PROFILE_VAR(ofdm_mod_start); + if (config_profile) machdep_profile_init(); + + struct OFDM_CONFIG *ofdm_config; + + ofdm = ofdm_create(NULL); + assert(ofdm != NULL); + + /* Get a copy of the actual modem config */ + ofdm_config = ofdm_get_config_param(ofdm); + + ldpc_codes_setup(&ldpc, "HRA_112_112"); + + Nbitsperframe = ofdm_get_bits_per_frame(ofdm); + int Ndatabitsperframe; + if (config_ldpc_en) { + Ndatabitsperframe = ldpc.data_bits_per_frame; + } else { + Ndatabitsperframe = ofdm_get_bits_per_frame(ofdm) - ofdm->nuwbits - ofdm->ntxtbits; + } + + Nsamperframe = ofdm_get_samples_per_frame(ofdm); +// int ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits; + + if (config_verbose) { + ofdm_set_verbose(ofdm, config_verbose); + fprintf(stderr, "Nsamperframe: %d, Nbitsperframe: %d \n", Nsamperframe, Nbitsperframe); + } + + int ofdm_ntxtbits = ofdm_config->txtbits; + + uint8_t tx_bits_char[Ndatabitsperframe]; + int16_t tx_scaled[Nsamperframe]; + uint8_t txt_bits_char[ofdm_ntxtbits]; + + for(i=0; i< ofdm_ntxtbits; i++) { + txt_bits_char[i] = 0; + } + + if (config_verbose) { + ofdm_print_info(ofdm); + } + + int sin = open("stm_in.raw", O_RDONLY); + if (sin < 0) { + printf("Error opening input file\n"); + exit(1); + } + + int sout = open("mod.raw", O_WRONLY|O_TRUNC|O_CREAT, 0666); + if (sout < 0) { + printf("Error opening output file\n"); + exit(1); + } + + while (read(sin, tx_bits_char, sizeof(char) * Ndatabitsperframe) == Ndatabitsperframe) { + fprintf(stderr, "Frame %d\n", frame); + + if (config_profile) { PROFILE_SAMPLE(ofdm_mod_start); } + + if (config_ldpc_en) { + + complex float tx_sams[Nsamperframe]; + ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char, txt_bits_char); + + for(i=0; i<Nsamperframe; i++) { + tx_scaled[i] = crealf(tx_sams[i]); + } + + } else { // !config_ldpc_en + + uint8_t tx_frame[Nbitsperframe]; + ofdm_assemble_qpsk_modem_packet(ofdm, tx_frame, tx_bits_char, txt_bits_char); + + int tx_bits[Nbitsperframe]; + for(i=0; i<Nbitsperframe; i++) { + tx_bits[i] = tx_frame[i]; + } + + if (config_verbose >=3) { + fprintf(stderr, "\ntx_bits:\n"); + for (i = 0; i < Nbitsperframe; i++) { + fprintf(stderr, " %3d %8d\n", i, tx_bits[i]); + } + } + + COMP tx_sams[Nsamperframe]; + ofdm_mod(ofdm, tx_sams, tx_bits); + + if (config_verbose >=3) { + fprintf(stderr, "\ntx_sams:\n"); + for (i = 0; i < Nsamperframe; i++) { + fprintf(stderr, " %3d % f\n", i, (double)tx_sams[i].real); + } + } + + for(i=0; i<Nsamperframe; i++) { + tx_scaled[i] = tx_sams[i].real; + } + } + + if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_mod_start, " ofdm_mod"); + + write(sout, tx_scaled, sizeof(int16_t) * Nsamperframe); + + frame ++; + + } // while (fread(... + + close(sin); + close(sout); + + if (config_verbose) + printf("%d frames processed\n", frame); + + if (config_profile) { + printf("\nStart Profile Data\n"); + machdep_profile_print_logged_samples(); + printf("End Profile Data\n"); + } + + printf("\nEnd of Test\n"); + fclose(stdout); + fclose(stderr); + + return 0; +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/unittest/src/tst_semihost.c b/stm32/unittest/src/tst_semihost.c new file mode 100644 index 0000000..a48b7e5 --- /dev/null +++ b/stm32/unittest/src/tst_semihost.c @@ -0,0 +1,91 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <math.h> +#include <errno.h> + +#include "semihosting.h" + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "machdep.h" + +#define min(a, b) ((a < b) ? (a) : (b)) + +int main(int argc, char *argv[]) { + + semihosting_init(); + + printf("semihosting test - stdout\n"); + fprintf(stderr, "semihosting test - stderr\n"); + + uint8_t buf[128]; + int count; + int i; + + FILE *fin = fopen("stm_in.raw", "rb"); + if (!fin) { + fprintf(stderr, "Error %d opening fin\n", errno); + } + setbuf(fin, NULL); + + FILE *fout = fopen("stm_out.raw", "wb"); + if (!fout) { + fprintf(stderr, "Error %d opening fout\n", errno); + } + setbuf(fout, NULL); + + // Unrolled while loop for simpler debugging: + // Pass 0: expect 16 bytes 00-0f + printf("Pass 0: feof(fin) = %d\n", feof(fin)); + count = fread(&buf[0], 1, 16, fin); + printf("read %d bytes: ", count); + for (i=0; i<count; i++) printf(" %02x", buf[i]); + printf("\nfeof(fin) = %d\n", feof(fin)); + for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i]; + if (count) count = fwrite(&buf[0], 1, count, fout); + printf("Wrote %d bytes\n\n", count); + + // Pass 1: expect 16 bytes 10-1f + printf("Pass 1: feof(fin) = %d\n", feof(fin)); + count = fread(&buf[0], 1, 16, fin); + printf("read %d bytes: ", count); + for (i=0; i<count; i++) printf(" %02x", buf[i]); + printf("\nfeof(fin) = %d\n", feof(fin)); + for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i]; + if (count) count = fwrite(&buf[0], 1, count, fout); + printf("Wrote %d bytes\n\n", count); + + // Pass 2: expect 3 bytes 20-22 + printf("Pass 2: feof(fin) = %d\n", feof(fin)); + count = fread(&buf[0], 1, 16, fin); + printf("read %d bytes: ", count); + for (i=0; i<count; i++) printf(" %02x", buf[i]); + printf("\nfeof(fin) = %d\n", feof(fin)); + for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i]; + if (count) count = fwrite(&buf[0], 1, count, fout); + printf("Wrote %d bytes\n\n", count); + + // Pass 3: expect 0 result (EOF) + printf("Pass 3: feof(fin) = %d\n", feof(fin)); + count = fread(&buf[0], 1, 16, fin); + printf("read %d bytes: ", count); + for (i=0; i<count; i++) printf(" %02x", buf[i]); + printf("\nfeof(fin) = %d\n", feof(fin)); + for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i]; + if (count) count = fwrite(&buf[0], 1, count, fout); + printf("Wrote %d bytes\n\n", count); + + + fclose(fin); + fclose(fout); + + printf("End of test\n"); + fflush(stdout); + fflush(stderr); + + return 0; +} + +/* vi:set ts=4 et sts=4: */ diff --git a/stm32/usb_conf/usb_bsp.c b/stm32/usb_conf/usb_bsp.c new file mode 100644 index 0000000..339b3fd --- /dev/null +++ b/stm32/usb_conf/usb_bsp.c @@ -0,0 +1,337 @@ +/** + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_bsp.h" +#include "usbd_conf.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_exti.h" +#include "stm32f4xx_rcc.h" +#include "misc.h" + + +void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev) { + +} + +void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev,uint8_t state) { + +} + + +/** +* @brief USB_OTG_BSP_Init +* Initializes 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(EXTI_Line0); +} +/** +* @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/stm32/usb_conf/usb_bsp.h b/stm32/usb_conf/usb_bsp.h new file mode 100644 index 0000000..736f3d0 --- /dev/null +++ b/stm32/usb_conf/usb_bsp.h @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @file usb_bsp.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Specific api's relative to the used hardware platform + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_BSP__H__ +#define __USB_BSP__H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_core.h" +#include "stm32f4xx.h" + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_BSP + * @brief This file is the + * @{ + */ + + +/** @defgroup USB_BSP_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USB_BSP_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USB_BSP_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_BSP_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_BSP_Exported_FunctionsPrototype + * @{ + */ +void BSP_Init(void); + +void USB_OTG_BSP_Init (USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_BSP_uDelay (const uint32_t usec); +void USB_OTG_BSP_mDelay (const uint32_t msec); +void USB_OTG_BSP_EnableInterrupt (USB_OTG_CORE_HANDLE *pdev); +#ifdef USE_HOST_MODE +void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev); +void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev,uint8_t state); +#endif +/** + * @} + */ + +#endif //__USB_BSP__H__ + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_conf/usb_conf.h b/stm32/usb_conf/usb_conf.h new file mode 100644 index 0000000..bddd285 --- /dev/null +++ b/stm32/usb_conf/usb_conf.h @@ -0,0 +1,287 @@ +/** + ****************************************************************************** + * @file usb_conf.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* 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 */ + +#ifndef USE_USB_OTG_HS + //#define USE_USB_OTG_HS +#endif /* USE_USB_OTG_HS */ + +#ifndef USE_ULPI_PHY + //#define USE_ULPI_PHY +#endif /* USE_ULPI_PHY */ + +#ifndef USE_EMBEDDED_PHY + //#define USE_EMBEDDED_PHY +#endif /* USE_EMBEDDED_PHY */ + +#ifndef USE_I2C_PHY + //#define USE_I2C_PHY +#endif /* USE_I2C_PHY */ + + +#ifdef USE_USB_OTG_FS + #define USB_OTG_FS_CORE +#endif + +#ifdef USE_USB_OTG_HS + #define USB_OTG_HS_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. +*******************************************************************************/ + +/******************************************************************************* +* FIFO Size Configuration in Host mode +* +* (i) Receive data FIFO size = (Largest Packet Size / 4) + 1 or +* 2x (Largest Packet Size / 4) + 1, If a +* high-bandwidth channel or multiple isochronous +* channels are enabled +* +* (ii) For the host nonperiodic Transmit FIFO is the largest maximum packet size +* for all supported nonperiodic OUT channels. Typically, a space +* corresponding to two Largest Packet Size is recommended. +* +* (iii) The minimum amount of RAM required for Host periodic Transmit FIFO is +* the largest maximum packet size for all supported periodic OUT channels. +* If there is at least one High Bandwidth Isochronous OUT endpoint, +* then the space must be at least two times the maximum packet size for +* that channel. +*******************************************************************************/ + +/****************** USB OTG HS CONFIGURATION **********************************/ +#ifdef USB_OTG_HS_CORE + #define RX_FIFO_HS_SIZE 512 + #define TX0_FIFO_HS_SIZE 512 + #define TX1_FIFO_HS_SIZE 512 + #define TX2_FIFO_HS_SIZE 0 + #define TX3_FIFO_HS_SIZE 0 + #define TX4_FIFO_HS_SIZE 0 + #define TX5_FIFO_HS_SIZE 0 + #define TXH_NP_HS_FIFOSIZ 96 + #define TXH_P_HS_FIFOSIZ 96 + + //#define USB_OTG_HS_LOW_PWR_MGMT_SUPPORT + //#define USB_OTG_HS_SOF_OUTPUT_ENABLED + + //#define USB_OTG_INTERNAL_VBUS_ENABLED + #define USB_OTG_EXTERNAL_VBUS_ENABLED + + #ifdef USE_ULPI_PHY + #define USB_OTG_ULPI_PHY_ENABLED + #endif + #ifdef USE_EMBEDDED_PHY + #define USB_OTG_EMBEDDED_PHY_ENABLED + #endif + #ifdef USE_I2C_PHY + #define USB_OTG_I2C_PHY_ENABLED + #endif +//#define USB_OTG_HS_INTERNAL_DMA_ENABLED + #define USB_OTG_HS_DEDICATED_EP1_ENABLED +#endif + +/****************** 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 TXH_NP_FS_FIFOSIZ 96 + #define TXH_P_FS_FIFOSIZ 96 + + //#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 dependent 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/stm32/usb_conf/usbd_conf.h b/stm32/usb_conf/usbd_conf.h new file mode 100644 index 0000000..9fc6d51 --- /dev/null +++ b/stm32/usb_conf/usbd_conf.h @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @file usbd_conf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CONF__H__ +#define __USBD_CONF__H__ + +/** @defgroup USB_CONF_Exported_Defines + * @{ + */ +#define USBD_CFG_MAX_NUM 1 +#define USBD_ITF_MAX_NUM 1 +#define USB_MAX_STR_DESC_SIZ 100 + +/** @defgroup USB_VCP_Class_Layer_Parameter + * @{ + */ +#define CDC_IN_EP 0x81 /* EP1 for data IN */ +#define CDC_OUT_EP 0x01 /* EP1 for data OUT */ +#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */ + +/* CDC Endpoints parameters: you can fine tune these values depending on the needed baudrates and performance. */ +#ifdef USE_USB_OTG_HS + #define CDC_DATA_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */ + #define CDC_CMD_PACKET_SZE 8 /* Control Endpoint Packet size */ + + #define CDC_IN_FRAME_INTERVAL 40 /* Number of micro-frames between IN transfers */ + #define APP_RX_DATA_SIZE 2048 /* Total size of IN buffer: + APP_RX_DATA_SIZE*8/MAX_BAUDARATE*1000 should be > CDC_IN_FRAME_INTERVAL*8 */ +#else + #define CDC_DATA_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */ + #define CDC_CMD_PACKET_SZE 8 /* Control Endpoint Packet size */ + + #define CDC_IN_FRAME_INTERVAL 5 /* Number of frames between IN transfers */ + + //#define APP_RX_DATA_SIZE 2048 /* Total size of IN buffer: */ + #define APP_RX_DATA_SIZE 10000 + +#endif /* USE_USB_OTG_HS */ + +#define APP_FOPS VCP_fops +/** + * @} + */ + +/** @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/stm32/usb_conf/usbd_desc.c b/stm32/usb_conf/usbd_desc.c new file mode 100644 index 0000000..3903b74 --- /dev/null +++ b/stm32/usb_conf/usbd_desc.c @@ -0,0 +1,324 @@ +/** + ****************************************************************************** + * @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 formatting 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include <assert.h> +#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 0x5740 + +/** @defgroup USB_String_Descriptors + * @{ + */ +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "STMicroelectronics" + +#define USBD_PRODUCT_HS_STRING "STM32 Virtual ComPort in HS mode" +#define USBD_SERIALNUMBER_HS_STRING "00000000050B" + +#define USBD_PRODUCT_FS_STRING "STM32 Virtual ComPort in FS Mode" +#define USBD_SERIALNUMBER_FS_STRING "00000000050C" + +#define USBD_CONFIGURATION_HS_STRING "VCP Config" +#define USBD_INTERFACE_HS_STRING "VCP Interface" + +#define USBD_CONFIGURATION_FS_STRING "VCP Config" +#define USBD_INTERFACE_FS_STRING "VCP 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 ((uint8_t*)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString ((uint8_t*)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length); + } + + assert(*length < USB_MAX_STR_DESC_SIZ); + + 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 ((uint8_t*)USBD_MANUFACTURER_STRING, USBD_StrDesc, length); + assert(*length < USB_MAX_STR_DESC_SIZ); + 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 ((uint8_t*)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString ((uint8_t*)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length); + } + assert(*length < USB_MAX_STR_DESC_SIZ); + 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 ((uint8_t*)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString ((uint8_t*)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); + } + assert(*length < USB_MAX_STR_DESC_SIZ); + 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 ((uint8_t*)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length); + } + else + { + USBD_GetString ((uint8_t*)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length); + } + assert(*length < USB_MAX_STR_DESC_SIZ); + return USBD_StrDesc; +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_conf/usbd_desc.h b/stm32/usb_conf/usbd_desc.h new file mode 100644 index 0000000..30c6f97 --- /dev/null +++ b/stm32/usb_conf/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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* 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/stm32/usb_conf/usbd_usr.c b/stm32/usb_conf/usbd_usr.c new file mode 100644 index 0000000..b009957 --- /dev/null +++ b/stm32/usb_conf/usbd_usr.c @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#include "usbd_usr.h" +#include "usbd_ioreq.h" + +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, +}; + + +/** +* @brief USBD_USR_Init +* Displays the message on LCD for host lib initialization +* @param None +* @retval None +*/ +void USBD_USR_Init(void) +{ + +} + +/** +* @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 Status +*/ +void USBD_USR_DeviceConfigured (void) +{ +} + + +/** +* @brief USBD_USR_DeviceConnected +* Displays the message on LCD on device connection Event +* @param None +* @retval Status +*/ +void USBD_USR_DeviceConnected (void) +{ +} + + +/** +* @brief USBD_USR_DeviceDisonnected +* Displays the message on LCD on device disconnection Event +* @param None +* @retval Status +*/ +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 */ +} + + diff --git a/stm32/usb_lib/cdc/usbd_cdc_core.c b/stm32/usb_lib/cdc/usbd_cdc_core.c new file mode 100644 index 0000000..30ec66d --- /dev/null +++ b/stm32/usb_lib/cdc/usbd_cdc_core.c @@ -0,0 +1,811 @@ +/** + ****************************************************************************** + * @file usbd_cdc_core.c + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief This file provides the high layer firmware functions to manage the + * following functionalities of the USB CDC Class: + * - Initialization and Configuration of high and low layer + * - Enumeration as CDC Device (and enumeration for each implemented memory interface) + * - OUT/IN data transfer + * - Command IN transfer (class requests management) + * - Error management + * + * @verbatim + * + * =================================================================== + * CDC Class Driver Description + * =================================================================== + * This driver manages the "Universal Serial Bus Class Definitions for Communications Devices + * Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus + * Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007" + * This driver implements the following aspects of the specification: + * - Device descriptor management + * - Configuration descriptor management + * - Enumeration as CDC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN) + * - Requests management (as described in section 6.2 in specification) + * - Abstract Control Model compliant + * - Union Functional collection (using 1 IN endpoint for control) + * - Data interface class + + * @note + * For the Abstract Control Model, this core allows only transmitting the requests to + * lower layer dispatcher (ie. usbd_cdc_vcp.c/.h) which should manage each request and + * perform relative actions. + * + * These aspects may be enriched or modified for a specific user application. + * + * This driver doesn't implement the following aspects of the specification + * (but it is possible to manage these features with some modifications on this driver): + * - Any class-specific aspect relative to communication classes should be managed by user application. + * - All communication classes other than PSTN are not managed + * + * @endverbatim + * + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc_core.h" +#include "usbd_desc.h" +#include "usbd_req.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup usbd_cdc + * @brief usbd core module + * @{ + */ + +/** @defgroup usbd_cdc_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup usbd_cdc_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup usbd_cdc_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup usbd_cdc_Private_FunctionPrototypes + * @{ + */ + +/********************************************* + CDC Device library callbacks + *********************************************/ +static uint8_t usbd_cdc_Init (void *pdev, uint8_t cfgidx); +static uint8_t usbd_cdc_DeInit (void *pdev, uint8_t cfgidx); +static uint8_t usbd_cdc_Setup (void *pdev, USB_SETUP_REQ *req); +static uint8_t usbd_cdc_EP0_RxReady (void *pdev); +static uint8_t usbd_cdc_DataIn (void *pdev, uint8_t epnum); +static uint8_t usbd_cdc_DataOut (void *pdev, uint8_t epnum); +static uint8_t usbd_cdc_SOF (void *pdev); + +/********************************************* + CDC specific management functions + *********************************************/ +static void Handle_USBAsynchXfer (void *pdev); +static uint8_t *USBD_cdc_GetCfgDesc (uint8_t speed, uint16_t *length); +#ifdef USE_USB_OTG_HS +static uint8_t *USBD_cdc_GetOtherCfgDesc (uint8_t speed, uint16_t *length); +#endif +/** + * @} + */ + +/** @defgroup usbd_cdc_Private_Variables + * @{ + */ +extern CDC_IF_Prop_TypeDef APP_FOPS; +extern uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC]; + +#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 uint8_t usbd_cdc_CfgDesc [USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END ; + +#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 uint8_t usbd_cdc_OtherCfgDesc [USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END ; + +#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 static __IO uint32_t usbd_cdc_AltSet __ALIGN_END = 0; + +#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 uint8_t USB_Rx_Buffer [CDC_DATA_MAX_PACKET_SIZE] __ALIGN_END ; + +#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 uint8_t APP_Rx_Buffer [APP_RX_DATA_SIZE] __ALIGN_END ; + + +#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 uint8_t CmdBuff[CDC_CMD_PACKET_SZE] __ALIGN_END ; + +uint32_t APP_Rx_ptr_in = 0; +uint32_t APP_Rx_ptr_out = 0; +uint32_t APP_Rx_length = 0; + +uint8_t USB_Tx_State = 0; + +static uint32_t cdcCmd = 0xFF; +static uint32_t cdcLen = 0; + +/* CDC interface class callbacks structure */ +USBD_Class_cb_TypeDef USBD_CDC_cb = +{ + usbd_cdc_Init, + usbd_cdc_DeInit, + usbd_cdc_Setup, + NULL, /* EP0_TxSent, */ + usbd_cdc_EP0_RxReady, + usbd_cdc_DataIn, + usbd_cdc_DataOut, + usbd_cdc_SOF, + NULL, + NULL, + USBD_cdc_GetCfgDesc, +#ifdef USE_USB_OTG_HS + USBD_cdc_GetOtherCfgDesc, /* use same cobfig as per FS */ +#endif /* USE_USB_OTG_HS */ +}; + +#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 CDC device Configuration Descriptor */ +__ALIGN_BEGIN uint8_t usbd_cdc_CfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = +{ + /*Configuration Descriptor*/ + 0x09, /* bLength: Configuration Descriptor size */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ + USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ + 0x00, + 0x02, /* bNumInterfaces: 2 interface */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ + 0xC0, /* bmAttributes: self powered */ + 0x32, /* MaxPower 0 mA */ + + /*---------------------------------------------------------------------------*/ + + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + /* Interface descriptor type */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x01, /* bInterfaceProtocol: Common AT commands */ + 0x00, /* iInterface: */ + + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ + 0x01, /* bDataInterface: 1 */ + + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ + 0x00, /* bMasterInterface: Communication class interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + + /*Endpoint 2 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_CMD_EP, /* bEndpointAddress */ + 0x03, /* bmAttributes: Interrupt */ + LOBYTE(CDC_CMD_PACKET_SZE), /* wMaxPacketSize: */ + HIBYTE(CDC_CMD_PACKET_SZE), +#ifdef USE_USB_OTG_HS + 0x10, /* bInterval: */ +#else + 0xFF, /* bInterval: */ +#endif /* USE_USB_OTG_HS */ + + /*---------------------------------------------------------------------------*/ + + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ + 0x01, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x00, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + + /*Endpoint OUT Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_OUT_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes: Bulk */ + LOBYTE(CDC_DATA_MAX_PACKET_SIZE), /* wMaxPacketSize: */ + HIBYTE(CDC_DATA_MAX_PACKET_SIZE), + 0x00, /* bInterval: ignore for Bulk transfer */ + + /*Endpoint IN Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_IN_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes: Bulk */ + LOBYTE(CDC_DATA_MAX_PACKET_SIZE), /* wMaxPacketSize: */ + HIBYTE(CDC_DATA_MAX_PACKET_SIZE), + 0x00 /* bInterval: ignore for Bulk transfer */ +} ; + +#ifdef USE_USB_OTG_HS +#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 uint8_t usbd_cdc_OtherCfgDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = +{ + 0x09, /* bLength: Configuration Descriptor size */ + USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION, + USB_CDC_CONFIG_DESC_SIZ, + 0x00, + 0x02, /* bNumInterfaces: 2 interfaces */ + 0x01, /* bConfigurationValue: */ + 0x04, /* iConfiguration: */ + 0xC0, /* bmAttributes: */ + 0x32, /* MaxPower 100 mA */ + + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + /* Interface descriptor type */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x01, /* bInterfaceProtocol: Common AT commands */ + 0x00, /* iInterface: */ + + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ + 0x01, /* bDataInterface: 1 */ + + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ + 0x00, /* bMasterInterface: Communication class interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + + /*Endpoint 2 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_CMD_EP, /* bEndpointAddress */ + 0x03, /* bmAttributes: Interrupt */ + LOBYTE(CDC_CMD_PACKET_SZE), /* wMaxPacketSize: */ + HIBYTE(CDC_CMD_PACKET_SZE), + 0xFF, /* bInterval: */ + + /*---------------------------------------------------------------------------*/ + + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ + 0x01, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x00, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + + /*Endpoint OUT Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_OUT_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes: Bulk */ + 0x40, /* wMaxPacketSize: */ + 0x00, + 0x00, /* bInterval: ignore for Bulk transfer */ + + /*Endpoint IN Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + CDC_IN_EP, /* bEndpointAddress */ + 0x02, /* bmAttributes: Bulk */ + 0x40, /* wMaxPacketSize: */ + 0x00, + 0x00 /* bInterval */ +}; +#endif /* USE_USB_OTG_HS */ + +/** + * @} + */ + +/** @defgroup usbd_cdc_Private_Functions + * @{ + */ + +/** + * @brief usbd_cdc_Init + * Initilaize the CDC interface + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usbd_cdc_Init (void *pdev, + uint8_t cfgidx) +{ + uint8_t *pbuf; + + /* Open EP IN */ + DCD_EP_Open(pdev, + CDC_IN_EP, + CDC_DATA_IN_PACKET_SIZE, + USB_OTG_EP_BULK); + + /* Open EP OUT */ + DCD_EP_Open(pdev, + CDC_OUT_EP, + CDC_DATA_OUT_PACKET_SIZE, + USB_OTG_EP_BULK); + + /* Open Command IN EP */ + DCD_EP_Open(pdev, + CDC_CMD_EP, + CDC_CMD_PACKET_SZE, + USB_OTG_EP_INT); + + pbuf = (uint8_t *)USBD_DeviceDesc; + pbuf[4] = DEVICE_CLASS_CDC; + pbuf[5] = DEVICE_SUBCLASS_CDC; + + /* Initialize the Interface physical components */ + APP_FOPS.pIf_Init(); + + /* Prepare Out endpoint to receive next packet */ + DCD_EP_PrepareRx(pdev, + CDC_OUT_EP, + (uint8_t*)(USB_Rx_Buffer), + CDC_DATA_OUT_PACKET_SIZE); + + return USBD_OK; +} + +/** + * @brief usbd_cdc_Init + * DeInitialize the CDC layer + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usbd_cdc_DeInit (void *pdev, + uint8_t cfgidx) +{ + /* Open EP IN */ + DCD_EP_Close(pdev, + CDC_IN_EP); + + /* Open EP OUT */ + DCD_EP_Close(pdev, + CDC_OUT_EP); + + /* Open Command IN EP */ + DCD_EP_Close(pdev, + CDC_CMD_EP); + + /* Restore default state of the Interface physical components */ + APP_FOPS.pIf_DeInit(); + + return USBD_OK; +} + +/** + * @brief usbd_cdc_Setup + * Handle the CDC specific requests + * @param pdev: instance + * @param req: usb requests + * @retval status + */ +static uint8_t usbd_cdc_Setup (void *pdev, + USB_SETUP_REQ *req) +{ + uint16_t len = 0; + uint8_t *pbuf; + + switch (req->bmRequest & USB_REQ_TYPE_MASK) + { + /* CDC Class Requests -------------------------------*/ + case USB_REQ_TYPE_CLASS : + /* Check if the request is a data setup packet */ + if (req->wLength) + { + /* Check if the request is Device-to-Host */ + if (req->bmRequest & 0x80) + { + /* Get the data to be sent to Host from interface layer */ + APP_FOPS.pIf_Ctrl(req->bRequest, CmdBuff, req->wLength); + + /* Send the data to the host */ + USBD_CtlSendData (pdev, + CmdBuff, + req->wLength); + } + else /* Host-to-Device request */ + { + /* Set the value of the current command to be processed */ + cdcCmd = req->bRequest; + cdcLen = req->wLength; + + /* Prepare the reception of the buffer over EP0 + Next step: the received data will be managed in usbd_cdc_EP0_TxSent() + function. */ + USBD_CtlPrepareRx (pdev, + CmdBuff, + req->wLength); + } + } + else /* No Data request */ + { + /* Transfer the command to the interface layer */ + APP_FOPS.pIf_Ctrl(req->bRequest, NULL, 0); + } + + return USBD_OK; + + default: + USBD_CtlError (pdev, req); + return USBD_FAIL; + + + + /* Standard Requests -------------------------------*/ + case USB_REQ_TYPE_STANDARD: + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + if( (req->wValue >> 8) == CDC_DESCRIPTOR_TYPE) + { +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + pbuf = usbd_cdc_Desc; +#else + pbuf = usbd_cdc_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM); +#endif + len = MIN(USB_CDC_DESC_SIZ , req->wLength); + } + + USBD_CtlSendData (pdev, + pbuf, + len); + break; + + case USB_REQ_GET_INTERFACE : + USBD_CtlSendData (pdev, + (uint8_t *)&usbd_cdc_AltSet, + 1); + break; + + case USB_REQ_SET_INTERFACE : + if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM) + { + usbd_cdc_AltSet = (uint8_t)(req->wValue); + } + else + { + /* Call the error management function (command will be nacked */ + USBD_CtlError (pdev, req); + } + break; + } + } + return USBD_OK; +} + +/** + * @brief usbd_cdc_EP0_RxReady + * Data received on control endpoint + * @param pdev: device device instance + * @retval status + */ +static uint8_t usbd_cdc_EP0_RxReady (void *pdev) +{ + if (cdcCmd != NO_CMD) + { + /* Process the data */ + APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen); + + /* Reset the command variable to default value */ + cdcCmd = NO_CMD; + } + + return USBD_OK; +} + +/** + * @brief usbd_audio_DataIn + * Data sent on non-control IN endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t usbd_cdc_DataIn (void *pdev, uint8_t epnum) +{ + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + if (USB_Tx_State == 1) + { + if (APP_Rx_length == 0) + { + USB_Tx_State = 0; + } + else + { + if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE){ + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = CDC_DATA_IN_PACKET_SIZE; + + APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE; + APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE; + } + else + { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = APP_Rx_length; + + APP_Rx_ptr_out += APP_Rx_length; + APP_Rx_length = 0; + } + + /* Prepare the available data buffer to be sent on IN endpoint */ + DCD_EP_Tx (pdev, + CDC_IN_EP, + (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], + USB_Tx_length); + } + } + + return USBD_OK; +} + +/** + * @brief usbd_audio_DataOut + * Data received on non-control Out endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t usbd_cdc_DataOut (void *pdev, uint8_t epnum) +{ + uint16_t USB_Rx_Cnt; + + /* Get the received data buffer and update the counter */ + USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count; + + /* USB data will be immediately processed, this allow next USB traffic being + NAKed till the end of the application Xfer */ + APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt); + + /* Prepare Out endpoint to receive next packet */ + DCD_EP_PrepareRx(pdev, + CDC_OUT_EP, + (uint8_t*)(USB_Rx_Buffer), + CDC_DATA_OUT_PACKET_SIZE); + + return USBD_OK; +} + +/** + * @brief usbd_audio_SOF + * Start Of Frame event management + * @param pdev: instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t usbd_cdc_SOF (void *pdev) +{ + static uint32_t FrameCount = 0; + + if (FrameCount++ == CDC_IN_FRAME_INTERVAL) + { + /* Reset the frame counter */ + FrameCount = 0; + + /* Check the data to be sent through IN pipe */ + Handle_USBAsynchXfer(pdev); + } + + return USBD_OK; +} + +/** + * @brief Handle_USBAsynchXfer + * Send data to USB + * @param pdev: instance + * @retval None + */ +static void Handle_USBAsynchXfer (void *pdev) +{ + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + if(USB_Tx_State != 1) + { + if (APP_Rx_ptr_out == APP_RX_DATA_SIZE) + { + APP_Rx_ptr_out = 0; + } + + if(APP_Rx_ptr_out == APP_Rx_ptr_in) + { + USB_Tx_State = 0; + return; + } + + if(APP_Rx_ptr_out > APP_Rx_ptr_in) /* rollback */ + { + APP_Rx_length = APP_RX_DATA_SIZE - APP_Rx_ptr_out; + + } + else + { + APP_Rx_length = APP_Rx_ptr_in - APP_Rx_ptr_out; + + } +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + APP_Rx_length &= ~0x03; +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ + + if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE) + { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = CDC_DATA_IN_PACKET_SIZE; + + APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE; + APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE; + } + else + { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = APP_Rx_length; + + APP_Rx_ptr_out += APP_Rx_length; + APP_Rx_length = 0; + } + USB_Tx_State = 1; + + DCD_EP_Tx (pdev, + CDC_IN_EP, + (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], + USB_Tx_length); + } + +} + +/** + * @brief USBD_cdc_GetCfgDesc + * Return configuration descriptor + * @param speed : current device speed + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +static uint8_t *USBD_cdc_GetCfgDesc (uint8_t speed, uint16_t *length) +{ + *length = sizeof (usbd_cdc_CfgDesc); + return usbd_cdc_CfgDesc; +} + +/** + * @brief USBD_cdc_GetCfgDesc + * Return configuration descriptor + * @param speed : current device speed + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +#ifdef USE_USB_OTG_HS +static uint8_t *USBD_cdc_GetOtherCfgDesc (uint8_t speed, uint16_t *length) +{ + *length = sizeof (usbd_cdc_OtherCfgDesc); + return usbd_cdc_OtherCfgDesc; +} +#endif +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/cdc/usbd_cdc_core.h b/stm32/usb_lib/cdc/usbd_cdc_core.h new file mode 100644 index 0000000..43af268 --- /dev/null +++ b/stm32/usb_lib/cdc/usbd_cdc_core.h @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * @file usbd_cdc_core.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief header file for the usbd_cdc_core.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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ + +#ifndef __USB_CDC_CORE_H_ +#define __USB_CDC_CORE_H_ + +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup usbd_cdc + * @brief This file is the Header file for USBD_cdc.c + * @{ + */ + + +/** @defgroup usbd_cdc_Exported_Defines + * @{ + */ +#define USB_CDC_CONFIG_DESC_SIZ (67) +#define USB_CDC_DESC_SIZ (67-9) + +#define CDC_DESCRIPTOR_TYPE 0x21 + +#define DEVICE_CLASS_CDC 0x02 +#define DEVICE_SUBCLASS_CDC 0x00 + + +#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 STANDARD_ENDPOINT_DESC_SIZE 0x09 + +#define CDC_DATA_IN_PACKET_SIZE *(uint16_t *)(((USB_OTG_CORE_HANDLE *)pdev)->dev.pConfig_descriptor + 57) + +#define CDC_DATA_OUT_PACKET_SIZE *(uint16_t *)(((USB_OTG_CORE_HANDLE *)pdev)->dev.pConfig_descriptor + 64) + +/*---------------------------------------------------------------------*/ +/* CDC definitions */ +/*---------------------------------------------------------------------*/ + +/**************************************************/ +/* CDC Requests */ +/**************************************************/ +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 +#define NO_CMD 0xFF + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ +typedef struct _CDC_IF_PROP +{ + uint16_t (*pIf_Init) (void); + uint16_t (*pIf_DeInit) (void); + uint16_t (*pIf_Ctrl) (uint32_t Cmd, uint8_t* Buf, uint32_t Len); + uint16_t (*pIf_DataTx) (uint8_t* Buf, uint32_t Len); + uint16_t (*pIf_DataRx) (uint8_t* Buf, uint32_t Len); +} +CDC_IF_Prop_TypeDef; +/** + * @} + */ + + + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ + +extern USBD_Class_cb_TypeDef USBD_CDC_cb; +/** + * @} + */ + +/** @defgroup USB_CORE_Exported_Functions + * @{ + */ +/** + * @} + */ + +#endif // __USB_CDC_CORE_H_ +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/cdc/usbd_cdc_vcp.c b/stm32/usb_lib/cdc/usbd_cdc_vcp.c new file mode 100644 index 0000000..38efa97 --- /dev/null +++ b/stm32/usb_lib/cdc/usbd_cdc_vcp.c @@ -0,0 +1,280 @@ +/** + ****************************************************************************** + * @file usbd_cdc_vcp.c + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief Generic media access 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED +#pragma data_alignment = 4 +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_cdc_vcp.h" +#include "stm32f4xx_conf.h" +#include "stm32f4xx_usart.h" + +/* Private variables ---------------------------------------------------------*/ +LINE_CODING linecoding = { + 115200, /* baud rate*/ + 0x00, /* stop bits-1*/ + 0x00, /* parity - none*/ + 0x08 /* nb. of bits 8*/ +}; + +USART_InitTypeDef USART_InitStructure; + +/* These are external variables imported from CDC core to be used for IN + transfer management. */ +extern uint8_t APP_Rx_Buffer[]; /* Write CDC received data in this buffer. + These data will be sent over USB IN endpoint + in the CDC core functions. */ +extern uint32_t APP_Rx_ptr_in; /* Increment this pointer or roll it back to + start address when writing received data + in the buffer APP_Rx_Buffer. */ + +/* Private function prototypes -----------------------------------------------*/ +static uint16_t VCP_Init(void); +static uint16_t VCP_DeInit(void); +static uint16_t VCP_Ctrl(uint32_t Cmd, uint8_t* Buf, uint32_t Len); +static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len); +static uint16_t VCP_DataRx(uint8_t* Buf, uint32_t Len); + +CDC_IF_Prop_TypeDef VCP_fops = { VCP_Init, VCP_DeInit, VCP_Ctrl, VCP_DataTx, + VCP_DataRx }; + +/* Private functions ---------------------------------------------------------*/ +/** + * @brief VCP_Init + * Initializes the Media on the STM32 + * @param None + * @retval Result of the operation (USBD_OK in all cases) + */ +static uint16_t VCP_Init(void) { + return USBD_OK; +} + +/** + * @brief VCP_DeInit + * DeInitializes the Media on the STM32 + * @param None + * @retval Result of the operation (USBD_OK in all cases) + */ +static uint16_t VCP_DeInit(void) { + return USBD_OK; +} + +/** + * @brief VCP_Ctrl + * Manage the CDC class requests + * @param Cmd: Command code + * @param Buf: Buffer containing command data (request parameters) + * @param Len: Number of data to be sent (in bytes) + * @retval Result of the operation (USBD_OK in all cases) + */ +static uint16_t VCP_Ctrl(uint32_t Cmd, uint8_t* Buf, uint32_t Len) { + switch (Cmd) { + case SEND_ENCAPSULATED_COMMAND: + /* Not needed for this driver */ + break; + + case GET_ENCAPSULATED_RESPONSE: + /* Not needed for this driver */ + break; + + case SET_COMM_FEATURE: + /* Not needed for this driver */ + break; + + case GET_COMM_FEATURE: + /* Not needed for this driver */ + break; + + case CLEAR_COMM_FEATURE: + /* Not needed for this driver */ + break; + + case SET_LINE_CODING: + /* Not needed for this driver */ + break; + + case GET_LINE_CODING: + Buf[0] = (uint8_t) (linecoding.bitrate); + Buf[1] = (uint8_t) (linecoding.bitrate >> 8); + Buf[2] = (uint8_t) (linecoding.bitrate >> 16); + Buf[3] = (uint8_t) (linecoding.bitrate >> 24); + Buf[4] = linecoding.format; + Buf[5] = linecoding.paritytype; + Buf[6] = linecoding.datatype; + break; + + case SET_CONTROL_LINE_STATE: + /* Not needed for this driver */ + break; + + case SEND_BREAK: + /* Not needed for this driver */ + break; + + default: + break; + } + + return USBD_OK; +} + +/** + * @brief putchar + * Sends one char over the USB serial link. + * @param buf: char to be sent + * @retval none + */ + +void VCP_put_char(uint8_t buf) { + VCP_DataTx(&buf, 1); +} + +void VCP_send_str(uint8_t* buf) { + uint32_t i = 0; + while (*(buf + i)) { + i++; + } + VCP_DataTx(buf, i); +} + +void VCP_send_buffer(uint8_t* buf, int len) { + VCP_DataTx(buf, len); +} + +/** + * @brief VCP_DataTx + * CDC received data to be send over USB IN endpoint are managed in + * this function. + * @param Buf: Buffer of data to be sent + * @param Len: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else VCP_FAIL + */ +static uint16_t VCP_DataTx(uint8_t* Buf, uint32_t Len) { + uint32_t i = 0; + while (i < Len) { + APP_Rx_Buffer[APP_Rx_ptr_in] = *(Buf + i); + APP_Rx_ptr_in++; + i++; + /* To avoid buffer overflow */ + if (APP_Rx_ptr_in == APP_RX_DATA_SIZE) { + APP_Rx_ptr_in = 0; + } + } + + return USBD_OK; +} + +/** + * @brief VCP_DataRx + * Data received over USB OUT endpoint are sent over CDC interface + * through this function. + * + * @note + * This function will block any OUT packet reception on USB endpoint + * until exiting this function. If you exit this function before transfer + * is complete on CDC interface (ie. using DMA controller) it will result + * in receiving more data while previous ones are still not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else VCP_FAIL + */ + +#define APP_TX_BUF_SIZE 128 +uint8_t APP_Tx_Buffer[APP_TX_BUF_SIZE]; +uint32_t APP_tx_ptr_head; +uint32_t APP_tx_ptr_tail; + +static uint16_t VCP_DataRx(uint8_t* Buf, uint32_t Len) { + uint32_t i; + + for (i = 0; i < Len; i++) { + APP_Tx_Buffer[APP_tx_ptr_head] = *(Buf + i); + APP_tx_ptr_head++; + if (APP_tx_ptr_head == APP_TX_BUF_SIZE) + APP_tx_ptr_head = 0; + + if (APP_tx_ptr_head == APP_tx_ptr_tail) + return USBD_FAIL; + } + + return USBD_OK; +} + +int VCP_get_char(uint8_t *buf) { + if (APP_tx_ptr_head == APP_tx_ptr_tail) + return 0; + + *buf = APP_Tx_Buffer[APP_tx_ptr_tail]; + APP_tx_ptr_tail++; + if (APP_tx_ptr_tail == APP_TX_BUF_SIZE) + APP_tx_ptr_tail = 0; + + return 1; +} + +int VCP_get_string(uint8_t *buf) { + if (APP_tx_ptr_head == APP_tx_ptr_tail) + return 0; + + while (!APP_Tx_Buffer[APP_tx_ptr_tail] + || APP_Tx_Buffer[APP_tx_ptr_tail] == '\n' + || APP_Tx_Buffer[APP_tx_ptr_tail] == '\r') { + APP_tx_ptr_tail++; + if (APP_tx_ptr_tail == APP_TX_BUF_SIZE) + APP_tx_ptr_tail = 0; + if (APP_tx_ptr_head == APP_tx_ptr_tail) + return 0; + } + + int i = 0; + do { + *(buf + i) = APP_Tx_Buffer[i + APP_tx_ptr_tail]; + i++; + + if ((APP_tx_ptr_tail + i) == APP_TX_BUF_SIZE) + i = -APP_tx_ptr_tail; + if (APP_tx_ptr_head == (APP_tx_ptr_tail + i)) + return 0; + + } while (APP_Tx_Buffer[APP_tx_ptr_tail + i] + && APP_Tx_Buffer[APP_tx_ptr_tail + i] != '\n' + && APP_Tx_Buffer[APP_tx_ptr_tail + i] != '\r'); + + *(buf + i) = 0; + APP_tx_ptr_tail += i; + if (APP_tx_ptr_tail >= APP_TX_BUF_SIZE) + APP_tx_ptr_tail -= APP_TX_BUF_SIZE; + return i; +} + +/** + * @brief EVAL_COM_IRQHandler + * + * @param None. + * @retval None. + */ +void EVAL_COM_IRQHandler(void) { + +} + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/cdc/usbd_cdc_vcp.h b/stm32/usb_lib/cdc/usbd_cdc_vcp.h new file mode 100644 index 0000000..78f2c03 --- /dev/null +++ b/stm32/usb_lib/cdc/usbd_cdc_vcp.h @@ -0,0 +1,68 @@ +/** + ****************************************************************************** + * @file usbd_cdc_vcp.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief Header for usbd_cdc_vcp.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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CDC_VCP_H +#define __USBD_CDC_VCP_H + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_conf.h" + +#include "usbd_cdc_core.h" +#include "usbd_conf.h" +#include <stdint.h> + +/* Exported typef ------------------------------------------------------------*/ +/* The following structures groups all needed parameters to be configured for the + ComPort. These parameters can modified on the fly by the host through CDC class + command class requests. */ +typedef struct +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +}LINE_CODING; + +/* Exported constants --------------------------------------------------------*/ +/* The following define is used to route the USART IRQ handler to be used. + The IRQ handler function is implemented in the usbd_cdc_vcp.c file. */ +#ifdef USE_STM322xG_EVAL + #define EVAL_COM_IRQHandler USART3_IRQHandler +#elif defined(USE_STM3210C_EVAL) + #define EVAL_COM_IRQHandler USART2_IRQHandler +#endif /* USE_STM322xG_EVAL */ + +void VCP_put_char(uint8_t buf); +void VCP_send_str(uint8_t* buf); +int VCP_get_char(uint8_t *buf); +int VCP_get_string(uint8_t *buf); +void VCP_send_buffer(uint8_t* buf, int len); + +#define DEFAULT_CONFIG 0 +#define OTHER_CONFIG 1 + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +#endif /* __USBD_CDC_VCP_H */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_core.c b/stm32/usb_lib/core/usbd_core.c new file mode 100644 index 0000000..1faa5f7 --- /dev/null +++ b/stm32/usb_lib/core/usbd_core.c @@ -0,0 +1,476 @@ +/** + ****************************************************************************** + * @file usbd_core.c + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief This file provides all the USBD core functions. + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" +#include "usbd_req.h" +#include "usbd_ioreq.h" +#include "usb_dcd_int.h" +#include "usb_bsp.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY +* @{ +*/ + + +/** @defgroup USBD_CORE +* @brief usbd core module +* @{ +*/ + +/** @defgroup USBD_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Defines +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + + + +/** @defgroup USBD_CORE_Private_FunctionPrototypes +* @{ +*/ +static uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); +static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); +static uint8_t USBD_SOF(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_Reset(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_Suspend(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_Resume(USB_OTG_CORE_HANDLE *pdev); +#ifdef VBUS_SENSING_ENABLED +static uint8_t USBD_DevConnected(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_DevDisconnected(USB_OTG_CORE_HANDLE *pdev); +#endif +static uint8_t USBD_IsoINIncomplete(USB_OTG_CORE_HANDLE *pdev); +static uint8_t USBD_IsoOUTIncomplete(USB_OTG_CORE_HANDLE *pdev); +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Variables +* @{ +*/ + + + +USBD_DCD_INT_cb_TypeDef USBD_DCD_INT_cb = +{ + USBD_DataOutStage, + USBD_DataInStage, + USBD_SetupStage, + USBD_SOF, + USBD_Reset, + USBD_Suspend, + USBD_Resume, + USBD_IsoINIncomplete, + USBD_IsoOUTIncomplete, +#ifdef VBUS_SENSING_ENABLED +USBD_DevConnected, +USBD_DevDisconnected, +#endif +}; + +USBD_DCD_INT_cb_TypeDef *USBD_DCD_INT_fops = &USBD_DCD_INT_cb; +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Functions +* @{ +*/ + +/** +* @brief USBD_Init +* Initializes the device stack and load the class driver +* @param pdev: device instance +* @param core_address: USB OTG core ID +* @param class_cb: Class callback structure address +* @param usr_cb: User callback structure address +* @retval None +*/ +void USBD_Init(USB_OTG_CORE_HANDLE *pdev, + USB_OTG_CORE_ID_TypeDef coreID, + USBD_DEVICE *pDevice, + USBD_Class_cb_TypeDef *class_cb, + USBD_Usr_cb_TypeDef *usr_cb) +{ + /* Hardware Init */ + USB_OTG_BSP_Init(pdev); + + USBD_DeInit(pdev); + + /*Register class and user callbacks */ + pdev->dev.class_cb = class_cb; + pdev->dev.usr_cb = usr_cb; + pdev->dev.usr_device = pDevice; + + /* set USB OTG core params */ + DCD_Init(pdev , coreID); + + /* Upon Init call usr callback */ + pdev->dev.usr_cb->Init(); + + /* Enable Interrupts */ + USB_OTG_BSP_EnableInterrupt(pdev); +} + +/** +* @brief USBD_DeInit +* Re-Initialize th deviuce library +* @param pdev: device instance +* @retval status: status +*/ +USBD_Status USBD_DeInit(USB_OTG_CORE_HANDLE *pdev) +{ + /* Software Init */ + + return USBD_OK; +} + +/** +* @brief USBD_SetupStage +* Handle the setup stage +* @param pdev: device instance +* @retval status +*/ +static uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE *pdev) +{ + USB_SETUP_REQ req; + + USBD_ParseSetupRequest(pdev , &req); + + switch (req.bmRequest & 0x1F) + { + case USB_REQ_RECIPIENT_DEVICE: + USBD_StdDevReq (pdev, &req); + break; + + case USB_REQ_RECIPIENT_INTERFACE: + USBD_StdItfReq(pdev, &req); + break; + + case USB_REQ_RECIPIENT_ENDPOINT: + USBD_StdEPReq(pdev, &req); + break; + + default: + DCD_EP_Stall(pdev , req.bmRequest & 0x80); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_DataOutStage +* Handle data out stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) +{ + USB_OTG_EP *ep; + + if(epnum == 0) + { + ep = &pdev->dev.out_ep[0]; + if ( pdev->dev.device_state == USB_OTG_EP0_DATA_OUT) + { + if(ep->rem_data_len > ep->maxpacket) + { + ep->rem_data_len -= ep->maxpacket; + + if(pdev->cfg.dma_enable == 1) + { + /* in slave mode this, is handled by the RxSTSQLvl ISR */ + ep->xfer_buff += ep->maxpacket; + } + USBD_CtlContinueRx (pdev, + ep->xfer_buff, + MIN(ep->rem_data_len ,ep->maxpacket)); + } + else + { + if((pdev->dev.class_cb->EP0_RxReady != NULL)&& + (pdev->dev.device_status == USB_OTG_CONFIGURED)) + { + pdev->dev.class_cb->EP0_RxReady(pdev); + } + USBD_CtlSendStatus(pdev); + } + } + } + else if((pdev->dev.class_cb->DataOut != NULL)&& + (pdev->dev.device_status == USB_OTG_CONFIGURED)) + { + pdev->dev.class_cb->DataOut(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_DataInStage +* Handle data in stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) +{ + USB_OTG_EP *ep; + + if(epnum == 0) + { + ep = &pdev->dev.in_ep[0]; + if ( pdev->dev.device_state == USB_OTG_EP0_DATA_IN) + { + if(ep->rem_data_len > ep->maxpacket) + { + ep->rem_data_len -= ep->maxpacket; + if(pdev->cfg.dma_enable == 1) + { + /* in slave mode this, is handled by the TxFifoEmpty ISR */ + ep->xfer_buff += ep->maxpacket; + } + USBD_CtlContinueSendData (pdev, + ep->xfer_buff, + ep->rem_data_len); + } + else + { /* last packet is MPS multiple, so send ZLP packet */ + if((ep->total_data_len % ep->maxpacket == 0) && + (ep->total_data_len >= ep->maxpacket) && + (ep->total_data_len < ep->ctl_data_len )) + { + + USBD_CtlContinueSendData(pdev , NULL, 0); + ep->ctl_data_len = 0; + } + else + { + if((pdev->dev.class_cb->EP0_TxSent != NULL)&& + (pdev->dev.device_status == USB_OTG_CONFIGURED)) + { + pdev->dev.class_cb->EP0_TxSent(pdev); + } + USBD_CtlReceiveStatus(pdev); + } + } + } + } + else if((pdev->dev.class_cb->DataIn != NULL)&& + (pdev->dev.device_status == USB_OTG_CONFIGURED)) + { + pdev->dev.class_cb->DataIn(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ + +static uint8_t USBD_Reset(USB_OTG_CORE_HANDLE *pdev) +{ + /* Open EP0 OUT */ + DCD_EP_Open(pdev, + 0x00, + USB_OTG_MAX_EP0_SIZE, + EP_TYPE_CTRL); + + /* Open EP0 IN */ + DCD_EP_Open(pdev, + 0x80, + USB_OTG_MAX_EP0_SIZE, + EP_TYPE_CTRL); + + /* Upon Reset call usr call back */ + pdev->dev.device_status = USB_OTG_DEFAULT; + pdev->dev.usr_cb->DeviceReset(pdev->cfg.speed); + + return USBD_OK; +} + +/** +* @brief USBD_Resume +* Handle Resume event +* @param pdev: device instance +* @retval status +*/ + +static uint8_t USBD_Resume(USB_OTG_CORE_HANDLE *pdev) +{ + /* Upon Resume call usr call back */ + pdev->dev.usr_cb->DeviceResumed(); + pdev->dev.device_status = USB_OTG_CONFIGURED; + return USBD_OK; +} + + +/** +* @brief USBD_Suspend +* Handle Suspend event +* @param pdev: device instance +* @retval status +*/ + +static uint8_t USBD_Suspend(USB_OTG_CORE_HANDLE *pdev) +{ + + pdev->dev.device_status = USB_OTG_SUSPENDED; + /* Upon Resume call usr call back */ + pdev->dev.usr_cb->DeviceSuspended(); + return USBD_OK; +} + + +/** +* @brief USBD_SOF +* Handle SOF event +* @param pdev: device instance +* @retval status +*/ + +static uint8_t USBD_SOF(USB_OTG_CORE_HANDLE *pdev) +{ + if(pdev->dev.class_cb->SOF) + { + pdev->dev.class_cb->SOF(pdev); + } + return USBD_OK; +} +/** +* @brief USBD_SetCfg +* Configure device and start the interface +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status +*/ + +USBD_Status USBD_SetCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx) +{ + pdev->dev.class_cb->Init(pdev, cfgidx); + + /* Upon set config call usr call back */ + pdev->dev.usr_cb->DeviceConfigured(); + return USBD_OK; +} + +/** +* @brief USBD_ClrCfg +* Clear current configuration +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status: USBD_Status +*/ +USBD_Status USBD_ClrCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx) +{ + pdev->dev.class_cb->DeInit(pdev, cfgidx); + return USBD_OK; +} + +/** +* @brief USBD_IsoINIncomplete +* Handle iso in incomplete event +* @param pdev: device instance +* @retval status +*/ +static uint8_t USBD_IsoINIncomplete(USB_OTG_CORE_HANDLE *pdev) +{ + pdev->dev.class_cb->IsoINIncomplete(pdev); + return USBD_OK; +} + +/** +* @brief USBD_IsoOUTIncomplete +* Handle iso out incomplete event +* @param pdev: device instance +* @retval status +*/ +static uint8_t USBD_IsoOUTIncomplete(USB_OTG_CORE_HANDLE *pdev) +{ + pdev->dev.class_cb->IsoOUTIncomplete(pdev); + return USBD_OK; +} + +#ifdef VBUS_SENSING_ENABLED +/** +* @brief USBD_DevConnected +* Handle device connection event +* @param pdev: device instance +* @retval status +*/ +static uint8_t USBD_DevConnected(USB_OTG_CORE_HANDLE *pdev) +{ + pdev->dev.usr_cb->DeviceConnected(); + return USBD_OK; +} + +/** +* @brief USBD_DevDisconnected +* Handle device disconnection event +* @param pdev: device instance +* @retval status +*/ +static uint8_t USBD_DevDisconnected(USB_OTG_CORE_HANDLE *pdev) +{ + pdev->dev.usr_cb->DeviceDisconnected(); + pdev->dev.class_cb->DeInit(pdev, 0); + return USBD_OK; +} +#endif +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_lib/core/usbd_core.h b/stm32/usb_lib/core/usbd_core.h new file mode 100644 index 0000000..1fc8366 --- /dev/null +++ b/stm32/usb_lib/core/usbd_core.h @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file usbd_core.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief Header file for usbd_core.c + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CORE_H +#define __USBD_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usb_dcd.h" +#include "usbd_def.h" +#include "usbd_conf.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_CORE + * @brief This file is the Header file for usbd_core.c file + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ + +typedef enum { + USBD_OK = 0, + USBD_BUSY, + USBD_FAIL, +}USBD_Status; +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_FunctionsPrototype + * @{ + */ +void USBD_Init(USB_OTG_CORE_HANDLE *pdev, + USB_OTG_CORE_ID_TypeDef coreID, + USBD_DEVICE *pDevice, + USBD_Class_cb_TypeDef *class_cb, + USBD_Usr_cb_TypeDef *usr_cb); + +USBD_Status USBD_DeInit(USB_OTG_CORE_HANDLE *pdev); + +USBD_Status USBD_ClrCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx); + +USBD_Status USBD_SetCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx); + +/** + * @} + */ + +#endif /* __USBD_CORE_H */ + +/** + * @} + */ + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + + + diff --git a/stm32/usb_lib/core/usbd_def.h b/stm32/usb_lib/core/usbd_def.h new file mode 100644 index 0000000..40620c9 --- /dev/null +++ b/stm32/usb_lib/core/usbd_def.h @@ -0,0 +1,149 @@ +/** + ****************************************************************************** + * @file usbd_def.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief general defines for the usb device library + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_DEF_H +#define __USBD_DEF_H +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_DEF + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_DEF_Exported_Defines + * @{ + */ + +#ifndef NULL +#define NULL 0 +#endif + +#define USB_LEN_DEV_QUALIFIER_DESC 0x0A +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 + +#define USBD_IDX_LANGID_STR 0x00 +#define USBD_IDX_MFC_STR 0x01 +#define USBD_IDX_PRODUCT_STR 0x02 +#define USBD_IDX_SERIAL_STR 0x03 +#define USBD_IDX_CONFIG_STR 0x04 +#define USBD_IDX_INTERFACE_STR 0x05 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_MASK 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 1 +#define USB_DESC_TYPE_CONFIGURATION 2 +#define USB_DESC_TYPE_STRING 3 +#define USB_DESC_TYPE_INTERFACE 4 +#define USB_DESC_TYPE_ENDPOINT 5 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 + + +#define USB_CONFIG_REMOTE_WAKEUP 2 +#define USB_CONFIG_SELF_POWERED 1 + +#define USB_FEATURE_EP_HALT 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 +#define USB_FEATURE_TEST_MODE 2 + +/** + * @} + */ + + +/** @defgroup USBD_DEF_Exported_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_DEF_Exported_Macros + * @{ + */ +#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) +#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* __USBD_DEF_H */ + +/** + * @} + */ + +/** +* @} +*/ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_ioreq.c b/stm32/usb_lib/core/usbd_ioreq.c new file mode 100644 index 0000000..ea7cacf --- /dev/null +++ b/stm32/usb_lib/core/usbd_ioreq.c @@ -0,0 +1,237 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.c + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief This file provides the IO requests APIs for control endpoints. + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ioreq.h" +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_IOREQ + * @brief control I/O requests module + * @{ + */ + +/** @defgroup USBD_IOREQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Functions + * @{ + */ + +/** +* @brief USBD_CtlSendData +* send data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_Status USBD_CtlSendData (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len) +{ + USBD_Status ret = USBD_OK; + + pdev->dev.in_ep[0].total_data_len = len; + pdev->dev.in_ep[0].rem_data_len = len; + pdev->dev.device_state = USB_OTG_EP0_DATA_IN; + + DCD_EP_Tx (pdev, 0, pbuf, len); + + return ret; +} + +/** +* @brief USBD_CtlContinueSendData +* continue sending data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_Status USBD_CtlContinueSendData (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len) +{ + USBD_Status ret = USBD_OK; + + DCD_EP_Tx (pdev, 0, pbuf, len); + + + return ret; +} + +/** +* @brief USBD_CtlPrepareRx +* receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_Status USBD_CtlPrepareRx (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len) +{ + USBD_Status ret = USBD_OK; + + pdev->dev.out_ep[0].total_data_len = len; + pdev->dev.out_ep[0].rem_data_len = len; + pdev->dev.device_state = USB_OTG_EP0_DATA_OUT; + + DCD_EP_PrepareRx (pdev, + 0, + pbuf, + len); + + + return ret; +} + +/** +* @brief USBD_CtlContinueRx +* continue receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_Status USBD_CtlContinueRx (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len) +{ + USBD_Status ret = USBD_OK; + + DCD_EP_PrepareRx (pdev, + 0, + pbuf, + len); + return ret; +} +/** +* @brief USBD_CtlSendStatus +* send zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_Status USBD_CtlSendStatus (USB_OTG_CORE_HANDLE *pdev) +{ + USBD_Status ret = USBD_OK; + pdev->dev.device_state = USB_OTG_EP0_STATUS_IN; + DCD_EP_Tx (pdev, + 0, + NULL, + 0); + + USB_OTG_EP0_OutStart(pdev); + + return ret; +} + +/** +* @brief USBD_CtlReceiveStatus +* receive zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_Status USBD_CtlReceiveStatus (USB_OTG_CORE_HANDLE *pdev) +{ + USBD_Status ret = USBD_OK; + pdev->dev.device_state = USB_OTG_EP0_STATUS_OUT; + DCD_EP_PrepareRx ( pdev, + 0, + NULL, + 0); + + USB_OTG_EP0_OutStart(pdev); + + return ret; +} + + +/** +* @brief USBD_GetRxCount +* returns the received data length +* @param pdev: USB OTG device instance +* epnum: endpoint index +* @retval Rx Data blength +*/ +uint16_t USBD_GetRxCount (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) +{ + return pdev->dev.out_ep[epnum].xfer_count; +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_ioreq.h b/stm32/usb_lib/core/usbd_ioreq.h new file mode 100644 index 0000000..6858eba --- /dev/null +++ b/stm32/usb_lib/core/usbd_ioreq.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief header file for the usbd_ioreq.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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_IOREQ_H_ +#define __USBD_IOREQ_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" +#include "usbd_core.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_IOREQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_IOREQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Exported_Types + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_IOREQ_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_Status USBD_CtlSendData (USB_OTG_CORE_HANDLE *pdev, + uint8_t *buf, + uint16_t len); + +USBD_Status USBD_CtlContinueSendData (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_Status USBD_CtlPrepareRx (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_Status USBD_CtlContinueRx (USB_OTG_CORE_HANDLE *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_Status USBD_CtlSendStatus (USB_OTG_CORE_HANDLE *pdev); + +USBD_Status USBD_CtlReceiveStatus (USB_OTG_CORE_HANDLE *pdev); + +uint16_t USBD_GetRxCount (USB_OTG_CORE_HANDLE *pdev , + uint8_t epnum); + +/** + * @} + */ + +#endif /* __USBD_IOREQ_H_ */ + +/** + * @} + */ + +/** +* @} +*/ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_req.c b/stm32/usb_lib/core/usbd_req.c new file mode 100644 index 0000000..40fca32 --- /dev/null +++ b/stm32/usb_lib/core/usbd_req.c @@ -0,0 +1,868 @@ +/** + ****************************************************************************** + * @file usbd_req.c + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief This file provides the standard USB requests following chapter 9. + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_req.h" +#include "usbd_ioreq.h" +#include "usbd_desc.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_REQ + * @brief USB standard requests module + * @{ + */ + +/** @defgroup USBD_REQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_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 uint32_t USBD_ep_status __ALIGN_END = 0; + +#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 uint32_t USBD_default_cfg __ALIGN_END = 0; + +#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 uint32_t USBD_cfg_status __ALIGN_END = 0; + +#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 uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ] __ALIGN_END ; +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_FunctionPrototypes + * @{ + */ +static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_SetAddress(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_SetConfig(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_GetConfig(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_GetStatus(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_SetFeature(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static void USBD_ClrFeature(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +static uint8_t USBD_GetLen(uint8_t *buf); +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Functions + * @{ + */ + + +/** +* @brief USBD_StdDevReq +* Handle standard usb device requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_Status USBD_StdDevReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req) +{ + USBD_Status ret = USBD_OK; + + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + + USBD_GetDescriptor (pdev, req) ; + break; + + case USB_REQ_SET_ADDRESS: + USBD_SetAddress(pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + USBD_SetConfig (pdev , req); + break; + + case USB_REQ_GET_CONFIGURATION: + USBD_GetConfig (pdev , req); + break; + + case USB_REQ_GET_STATUS: + USBD_GetStatus (pdev , req); + break; + + + case USB_REQ_SET_FEATURE: + USBD_SetFeature (pdev , req); + break; + + case USB_REQ_CLEAR_FEATURE: + USBD_ClrFeature (pdev , req); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + + return ret; +} + +/** +* @brief USBD_StdItfReq +* Handle standard usb interface requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_Status USBD_StdItfReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req) +{ + USBD_Status ret = USBD_OK; + + switch (pdev->dev.device_status) + { + case USB_OTG_CONFIGURED: + + if (LOBYTE(req->wIndex) <= USBD_ITF_MAX_NUM) + { + pdev->dev.class_cb->Setup (pdev, req); + + if((req->wLength == 0)&& (ret == USBD_OK)) + { + USBD_CtlSendStatus(pdev); + } + } + else + { + USBD_CtlError(pdev , req); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + return ret; +} + +/** +* @brief USBD_StdEPReq +* Handle standard usb endpoint requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_Status USBD_StdEPReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req) +{ + + uint8_t ep_addr; + USBD_Status ret = USBD_OK; + + ep_addr = LOBYTE(req->wIndex); + + switch (req->bRequest) + { + + case USB_REQ_SET_FEATURE : + + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + DCD_EP_Stall(pdev , ep_addr); + } + break; + + case USB_OTG_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + DCD_EP_Stall(pdev , ep_addr); + + } + } + pdev->dev.class_cb->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_CLEAR_FEATURE : + + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + DCD_EP_Stall(pdev , ep_addr); + } + break; + + case USB_OTG_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + DCD_EP_ClrStall(pdev , ep_addr); + pdev->dev.class_cb->Setup (pdev, req); + } + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_GET_STATUS: + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + DCD_EP_Stall(pdev , ep_addr); + } + break; + + case USB_OTG_CONFIGURED: + + + if ((ep_addr & 0x80)== 0x80) + { + if(pdev->dev.in_ep[ep_addr & 0x7F].is_stall) + { + USBD_ep_status = 0x0001; + } + else + { + USBD_ep_status = 0x0000; + } + } + else if ((ep_addr & 0x80)== 0x00) + { + if(pdev->dev.out_ep[ep_addr].is_stall) + { + USBD_ep_status = 0x0001; + } + + else + { + USBD_ep_status = 0x0000; + } + } + USBD_CtlSendData (pdev, + (uint8_t *)&USBD_ep_status, + 2); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + default: + break; + } + return ret; +} +/** +* @brief USBD_GetDescriptor +* Handle Get Descriptor requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetDescriptor(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + uint16_t len; + uint8_t *pbuf; + + switch (req->wValue >> 8) + { + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->dev.usr_device->GetDeviceDescriptor(pdev->cfg.speed, &len); + if ((req->wLength == 64) ||( pdev->dev.device_status == USB_OTG_DEFAULT)) + { + len = 8; + } + break; + + case USB_DESC_TYPE_CONFIGURATION: + pbuf = (uint8_t *)pdev->dev.class_cb->GetConfigDescriptor(pdev->cfg.speed, &len); +#ifdef USB_OTG_HS_CORE + if((pdev->cfg.speed == USB_OTG_SPEED_FULL )&& + (pdev->cfg.phy_itface == USB_OTG_ULPI_PHY)) + { + pbuf = (uint8_t *)pdev->dev.class_cb->GetOtherConfigDescriptor(pdev->cfg.speed, &len); + } +#endif + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + pdev->dev.pConfig_descriptor = pbuf; + break; + + case USB_DESC_TYPE_STRING: + switch ((uint8_t)(req->wValue)) + { + case USBD_IDX_LANGID_STR: + pbuf = pdev->dev.usr_device->GetLangIDStrDescriptor(pdev->cfg.speed, &len); + break; + + case USBD_IDX_MFC_STR: + pbuf = pdev->dev.usr_device->GetManufacturerStrDescriptor(pdev->cfg.speed, &len); + break; + + case USBD_IDX_PRODUCT_STR: + pbuf = pdev->dev.usr_device->GetProductStrDescriptor(pdev->cfg.speed, &len); + break; + + case USBD_IDX_SERIAL_STR: + pbuf = pdev->dev.usr_device->GetSerialStrDescriptor(pdev->cfg.speed, &len); + break; + + case USBD_IDX_CONFIG_STR: + pbuf = pdev->dev.usr_device->GetConfigurationStrDescriptor(pdev->cfg.speed, &len); + break; + + case USBD_IDX_INTERFACE_STR: + pbuf = pdev->dev.usr_device->GetInterfaceStrDescriptor(pdev->cfg.speed, &len); + break; + + default: +#ifdef USB_SUPPORT_USER_STRING_DESC + pbuf = pdev->dev.class_cb->GetUsrStrDescriptor(pdev->cfg.speed, (req->wValue) , &len); + break; +#else + USBD_CtlError(pdev , req); + return; +#endif /* USBD_CtlError(pdev , req); */ + } + break; + case USB_DESC_TYPE_DEVICE_QUALIFIER: +#ifdef USB_OTG_HS_CORE + if(pdev->cfg.speed == USB_OTG_SPEED_HIGH ) + { + + pbuf = (uint8_t *)pdev->dev.class_cb->GetConfigDescriptor(pdev->cfg.speed, &len); + + USBD_DeviceQualifierDesc[4]= pbuf[14]; + USBD_DeviceQualifierDesc[5]= pbuf[15]; + USBD_DeviceQualifierDesc[6]= pbuf[16]; + + pbuf = USBD_DeviceQualifierDesc; + len = USB_LEN_DEV_QUALIFIER_DESC; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } +#else + USBD_CtlError(pdev , req); + return; +#endif + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: +#ifdef USB_OTG_HS_CORE + + if(pdev->cfg.speed == USB_OTG_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->dev.class_cb->GetOtherConfigDescriptor(pdev->cfg.speed, &len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } +#else + USBD_CtlError(pdev , req); + return; +#endif + + + default: + USBD_CtlError(pdev , req); + return; + } + + if((len != 0)&& (req->wLength != 0)) + { + + len = MIN(len , req->wLength); + + USBD_CtlSendData (pdev, + pbuf, + len); + } + +} + +/** +* @brief USBD_SetAddress +* Set device address +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetAddress(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + uint8_t dev_addr; + + if ((req->wIndex == 0) && (req->wLength == 0)) + { + dev_addr = (uint8_t)(req->wValue) & 0x7F; + + if (pdev->dev.device_status == USB_OTG_CONFIGURED) + { + USBD_CtlError(pdev , req); + } + else + { + pdev->dev.device_address = dev_addr; + DCD_EP_SetAddress(pdev, dev_addr); + USBD_CtlSendStatus(pdev); + + if (dev_addr != 0) + { + pdev->dev.device_status = USB_OTG_ADDRESSED; + } + else + { + pdev->dev.device_status = USB_OTG_DEFAULT; + } + } + } + else + { + USBD_CtlError(pdev , req); + } +} + +/** +* @brief USBD_SetConfig +* Handle Set device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetConfig(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + + static uint8_t cfgidx; + + cfgidx = (uint8_t)(req->wValue); + + if (cfgidx > USBD_CFG_MAX_NUM ) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + if (cfgidx) + { + pdev->dev.device_config = cfgidx; + pdev->dev.device_status = USB_OTG_CONFIGURED; + USBD_SetCfg(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + case USB_OTG_CONFIGURED: + if (cfgidx == 0) + { + pdev->dev.device_status = USB_OTG_ADDRESSED; + pdev->dev.device_config = cfgidx; + USBD_ClrCfg(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + + } + else if (cfgidx != pdev->dev.device_config) + { + /* Clear old configuration */ + USBD_ClrCfg(pdev , pdev->dev.device_config); + + /* set new configuration */ + pdev->dev.device_config = cfgidx; + USBD_SetCfg(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetConfig +* Handle Get device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetConfig(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + + if (req->wLength != 1) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev.device_status ) + { + case USB_OTG_ADDRESSED: + + USBD_CtlSendData (pdev, + (uint8_t *)&USBD_default_cfg, + 1); + break; + + case USB_OTG_CONFIGURED: + + USBD_CtlSendData (pdev, + &pdev->dev.device_config, + 1); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetStatus +* Handle Get Status request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetStatus(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + case USB_OTG_CONFIGURED: + + if (pdev->dev.DevRemoteWakeup) + { + USBD_cfg_status = USB_CONFIG_SELF_POWERED | USB_CONFIG_REMOTE_WAKEUP; + } + else + { + USBD_cfg_status = USB_CONFIG_SELF_POWERED; + } + + USBD_CtlSendData (pdev, + (uint8_t *)&USBD_cfg_status, + 1); + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + + +/** +* @brief USBD_SetFeature +* Handle Set device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetFeature(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + + USB_OTG_DCTL_TypeDef dctl; + uint8_t test_mode = 0; + + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev.DevRemoteWakeup = 1; + pdev->dev.class_cb->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + + else if ((req->wValue == USB_FEATURE_TEST_MODE) && + ((req->wIndex & 0xFF) == 0)) + { + dctl.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCTL); + + test_mode = req->wIndex >> 8; + switch (test_mode) + { + case 1: // TEST_J + dctl.b.tstctl = 1; + break; + + case 2: // TEST_K + dctl.b.tstctl = 2; + break; + + case 3: // TEST_SE0_NAK + dctl.b.tstctl = 3; + break; + + case 4: // TEST_PACKET + dctl.b.tstctl = 4; + break; + + case 5: // TEST_FORCE_ENABLE + dctl.b.tstctl = 5; + break; + } + USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCTL, dctl.d32); + USBD_CtlSendStatus(pdev); + } + +} + + +/** +* @brief USBD_ClrFeature +* Handle clear device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_ClrFeature(USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + switch (pdev->dev.device_status) + { + case USB_OTG_ADDRESSED: + case USB_OTG_CONFIGURED: + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev.DevRemoteWakeup = 0; + pdev->dev.class_cb->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + +/** +* @brief USBD_ParseSetupRequest +* Copy buffer into setup structure +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_ParseSetupRequest( USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + req->bmRequest = *(uint8_t *) (pdev->dev.setup_packet); + req->bRequest = *(uint8_t *) (pdev->dev.setup_packet + 1); + req->wValue = SWAPBYTE (pdev->dev.setup_packet + 2); + req->wIndex = SWAPBYTE (pdev->dev.setup_packet + 4); + req->wLength = SWAPBYTE (pdev->dev.setup_packet + 6); + + pdev->dev.in_ep[0].ctl_data_len = req->wLength ; + pdev->dev.device_state = USB_OTG_EP0_SETUP; +} + +/** +* @brief USBD_CtlError +* Handle USB low level Error +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_CtlError( USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req) +{ + if((req->bmRequest & 0x80) == 0x80) + { + DCD_EP_Stall(pdev , 0x80); + } + else + { + if(req->wLength == 0) + { + DCD_EP_Stall(pdev , 0x80); + } + else + { + DCD_EP_Stall(pdev , 0); + } + } + USB_OTG_EP0_OutStart(pdev); +} + + +/** + * @brief USBD_GetString + * Convert Ascii string into unicode one + * @param desc : descriptor buffer + * @param unicode : Formatted string buffer (unicode) + * @param len : descriptor length + * @retval None + */ +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0; + + if (desc != NULL) + { + *len = USBD_GetLen(desc) * 2 + 2; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != NULL) + { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00; + } + } +} + +/** + * @brief USBD_GetLen + * return the string length + * @param buf : pointer to the ascii string buffer + * @retval string length + */ +static uint8_t USBD_GetLen(uint8_t *buf) +{ + uint8_t len = 0; + + while (*buf != NULL) + { + len++; + buf++; + } + + return len; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_req.h b/stm32/usb_lib/core/usbd_req.h new file mode 100644 index 0000000..f73bb45 --- /dev/null +++ b/stm32/usb_lib/core/usbd_req.h @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * @file usbd_req.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief header file for the usbd_req.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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USB_REQUEST_H_ +#define __USB_REQUEST_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" +#include "usbd_core.h" +#include "usbd_conf.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_REQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_REQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Exported_Types + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_REQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_Status USBD_StdDevReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req); +USBD_Status USBD_StdItfReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req); +USBD_Status USBD_StdEPReq (USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req); +void USBD_ParseSetupRequest( USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +void USBD_CtlError( USB_OTG_CORE_HANDLE *pdev, + USB_SETUP_REQ *req); + +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len); +/** + * @} + */ + +#endif /* __USB_REQUEST_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/core/usbd_usr.h b/stm32/usb_lib/core/usbd_usr.h new file mode 100644 index 0000000..976cc13 --- /dev/null +++ b/stm32/usb_lib/core/usbd_usr.h @@ -0,0 +1,135 @@ +/** + ****************************************************************************** + * @file usbd_usr.h + * @author MCD Application Team + * @version V1.0.0 + * @date 22-July-2011 + * @brief Header file for usbd_usr.c + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_USR_H__ +#define __USBD_USR_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" + + +/** @addtogroup USBD_USER + * @{ + */ + +/** @addtogroup USBD_MSC_DEMO_USER_CALLBACKS + * @{ + */ + +/** @defgroup USBD_USR + * @brief This file is the Header file for usbd_usr.c + * @{ + */ + + +/** @defgroup USBD_USR_Exported_Types + * @{ + */ + +extern USBD_Usr_cb_TypeDef USR_cb; +extern USBD_Usr_cb_TypeDef USR_FS_cb; +extern USBD_Usr_cb_TypeDef USR_HS_cb; + + + +/** + * @} + */ + + + +/** @defgroup USBD_USR_Exported_Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_USR_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_USR_Exported_Variables + * @{ + */ + +void USBD_USR_Init(void); +void USBD_USR_DeviceReset (uint8_t speed); +void USBD_USR_DeviceConfigured (void); +void USBD_USR_DeviceSuspended(void); +void USBD_USR_DeviceResumed(void); + +void USBD_USR_DeviceConnected(void); +void USBD_USR_DeviceDisconnected(void); + +void USBD_USR_FS_Init(void); +void USBD_USR_FS_DeviceReset (uint8_t speed); +void USBD_USR_FS_DeviceConfigured (void); +void USBD_USR_FS_DeviceSuspended(void); +void USBD_USR_FS_DeviceResumed(void); + +void USBD_USR_FS_DeviceConnected(void); +void USBD_USR_FS_DeviceDisconnected(void); + +void USBD_USR_HS_Init(void); +void USBD_USR_HS_DeviceReset (uint8_t speed); +void USBD_USR_HS_DeviceConfigured (void); +void USBD_USR_HS_DeviceSuspended(void); +void USBD_USR_HS_DeviceResumed(void); + +void USBD_USR_HS_DeviceConnected(void); +void USBD_USR_HS_DeviceDisconnected(void); + +/** + * @} + */ + +/** @defgroup USBD_USR_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + +#endif /*__USBD_USR_H__*/ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + + + + diff --git a/stm32/usb_lib/otg/usb_core.c b/stm32/usb_lib/otg/usb_core.c new file mode 100644 index 0000000..6931ea5 --- /dev/null +++ b/stm32/usb_lib/otg/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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* 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 common 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, *((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 ) + { + *(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/stm32/usb_lib/otg/usb_core.h b/stm32/usb_lib/otg/usb_core.h new file mode 100644 index 0000000..acd1f1c --- /dev/null +++ b/stm32/usb_lib/otg/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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* 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/stm32/usb_lib/otg/usb_dcd.c b/stm32/usb_lib/otg/usb_dcd.c new file mode 100644 index 0000000..43dafc6 --- /dev/null +++ b/stm32/usb_lib/otg/usb_dcd.c @@ -0,0 +1,475 @@ +/** + ****************************************************************************** + * @file usb_dcd.c + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Peripheral Device Interface 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#include "usb_conf.h" +#ifdef USE_DEVICE_MODE +/* Includes ------------------------------------------------------------------*/ +#include "usb_dcd.h" +#include "usb_bsp.h" + + +/** @addtogroup USB_OTG_DRIVER +* @{ +*/ + +/** @defgroup USB_DCD +* @brief This file is the interface between EFSL and Host mass-storage class +* @{ +*/ + + +/** @defgroup USB_DCD_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + + +/** @defgroup USB_DCD_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_Private_FunctionPrototypes +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USB_DCD_Private_Functions +* @{ +*/ + + + +void DCD_Init(USB_OTG_CORE_HANDLE *pdev , + USB_OTG_CORE_ID_TypeDef coreID) +{ + uint32_t i; + USB_OTG_EP *ep; + + USB_OTG_SelectCore (pdev , coreID); + + pdev->dev.device_status = USB_OTG_DEFAULT; + pdev->dev.device_address = 0; + + /* Init ep structure */ + for (i = 0; i < pdev->cfg.dev_endpoints ; i++) + { + ep = &pdev->dev.in_ep[i]; + /* Init ep structure */ + ep->is_in = 1; + ep->num = i; + ep->tx_fifo_num = i; + /* Control until ep is actvated */ + ep->type = EP_TYPE_CTRL; + ep->maxpacket = USB_OTG_MAX_EP0_SIZE; + ep->xfer_buff = 0; + ep->xfer_len = 0; + } + + for (i = 0; i < pdev->cfg.dev_endpoints; i++) + { + ep = &pdev->dev.out_ep[i]; + /* Init ep structure */ + ep->is_in = 0; + ep->num = i; + ep->tx_fifo_num = i; + /* Control until ep is activated */ + ep->type = EP_TYPE_CTRL; + ep->maxpacket = USB_OTG_MAX_EP0_SIZE; + ep->xfer_buff = 0; + ep->xfer_len = 0; + } + + USB_OTG_DisableGlobalInt(pdev); + + /*Init the Core (common init.) */ + USB_OTG_CoreInit(pdev); + + + /* Force Device Mode*/ + USB_OTG_SetCurrentMode(pdev, DEVICE_MODE); + + /* Init Device */ + USB_OTG_CoreInitDev(pdev); + + + /* Enable USB Global interrupt */ + USB_OTG_EnableGlobalInt(pdev); +} + + +/** +* @brief Configure an EP +* @param pdev : Device instance +* @param epdesc : Endpoint Descriptor +* @retval : status +*/ +uint32_t DCD_EP_Open(USB_OTG_CORE_HANDLE *pdev , + uint8_t ep_addr, + uint16_t ep_mps, + uint8_t ep_type) +{ + USB_OTG_EP *ep; + + if ((ep_addr & 0x80) == 0x80) + { + ep = &pdev->dev.in_ep[ep_addr & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[ep_addr & 0x7F]; + } + ep->num = ep_addr & 0x7F; + + ep->is_in = (0x80 & ep_addr) != 0; + ep->maxpacket = ep_mps; + ep->type = ep_type; + if (ep->is_in) + { + /* Assign a Tx FIFO */ + ep->tx_fifo_num = ep->num; + } + /* Set initial data PID. */ + if (ep_type == USB_OTG_EP_BULK ) + { + ep->data_pid_start = 0; + } + USB_OTG_EPActivate(pdev , ep ); + return 0; +} +/** +* @brief called when an EP is disabled +* @param pdev: device instance +* @param ep_addr: endpoint address +* @retval : status +*/ +uint32_t DCD_EP_Close(USB_OTG_CORE_HANDLE *pdev , uint8_t ep_addr) +{ + USB_OTG_EP *ep; + + if ((ep_addr&0x80) == 0x80) + { + ep = &pdev->dev.in_ep[ep_addr & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[ep_addr & 0x7F]; + } + ep->num = ep_addr & 0x7F; + ep->is_in = (0x80 & ep_addr) != 0; + USB_OTG_EPDeactivate(pdev , ep ); + return 0; +} + + +/** +* @brief DCD_EP_PrepareRx +* @param pdev: device instance +* @param ep_addr: endpoint address +* @param pbuf: pointer to Rx buffer +* @param buf_len: data length +* @retval : status +*/ +uint32_t DCD_EP_PrepareRx( USB_OTG_CORE_HANDLE *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t buf_len) +{ + USB_OTG_EP *ep; + + ep = &pdev->dev.out_ep[ep_addr & 0x7F]; + + /*setup and start the Xfer */ + ep->xfer_buff = pbuf; + ep->xfer_len = buf_len; + ep->xfer_count = 0; + ep->is_in = 0; + ep->num = ep_addr & 0x7F; + + if (pdev->cfg.dma_enable == 1) + { + ep->dma_addr = (uint32_t)pbuf; + } + + if ( ep->num == 0 ) + { + USB_OTG_EP0StartXfer(pdev , ep); + } + else + { + USB_OTG_EPStartXfer(pdev, ep ); + } + return 0; +} + +/** +* @brief Transmit data over USB +* @param pdev: device instance +* @param ep_addr: endpoint address +* @param pbuf: pointer to Tx buffer +* @param buf_len: data length +* @retval : status +*/ +uint32_t DCD_EP_Tx ( USB_OTG_CORE_HANDLE *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint32_t buf_len) +{ + USB_OTG_EP *ep; + + ep = &pdev->dev.in_ep[ep_addr & 0x7F]; + + /* Setup and start the Transfer */ + ep->is_in = 1; + ep->num = ep_addr & 0x7F; + ep->xfer_buff = pbuf; + ep->dma_addr = (uint32_t)pbuf; + ep->xfer_count = 0; + ep->xfer_len = buf_len; + + if ( ep->num == 0 ) + { + USB_OTG_EP0StartXfer(pdev , ep); + } + else + { + USB_OTG_EPStartXfer(pdev, ep ); + } + return 0; +} + + +/** +* @brief Stall an endpoint. +* @param pdev: device instance +* @param epnum: endpoint address +* @retval : status +*/ +uint32_t DCD_EP_Stall (USB_OTG_CORE_HANDLE *pdev, uint8_t epnum) +{ + USB_OTG_EP *ep; + if ((0x80 & epnum) == 0x80) + { + ep = &pdev->dev.in_ep[epnum & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[epnum]; + } + + ep->is_stall = 1; + ep->num = epnum & 0x7F; + ep->is_in = ((epnum & 0x80) == 0x80); + + USB_OTG_EPSetStall(pdev , ep); + return (0); +} + + +/** +* @brief Clear stall condition on endpoints. +* @param pdev: device instance +* @param epnum: endpoint address +* @retval : status +*/ +uint32_t DCD_EP_ClrStall (USB_OTG_CORE_HANDLE *pdev, uint8_t epnum) +{ + USB_OTG_EP *ep; + if ((0x80 & epnum) == 0x80) + { + ep = &pdev->dev.in_ep[epnum & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[epnum]; + } + + ep->is_stall = 0; + ep->num = epnum & 0x7F; + ep->is_in = ((epnum & 0x80) == 0x80); + + USB_OTG_EPClearStall(pdev , ep); + return (0); +} + + +/** +* @brief This Function flushes the FIFOs. +* @param pdev: device instance +* @param epnum: endpoint address +* @retval : status +*/ +uint32_t DCD_EP_Flush (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) +{ + + if ((epnum & 0x80) == 0x80) + { + USB_OTG_FlushTxFifo(pdev, epnum & 0x7F); + } + else + { + USB_OTG_FlushRxFifo(pdev); + } + + return (0); +} + + +/** +* @brief This Function set USB device address +* @param pdev: device instance +* @param address: new device address +* @retval : status +*/ +void DCD_EP_SetAddress (USB_OTG_CORE_HANDLE *pdev, uint8_t address) +{ + USB_OTG_DCFG_TypeDef dcfg; + dcfg.d32 = 0; + dcfg.b.devaddr = address; + USB_OTG_MODIFY_REG32( &pdev->regs.DREGS->DCFG, 0, dcfg.d32); +} + +/** +* @brief Connect device (enable internal pull-up) +* @param pdev: device instance +* @retval : None +*/ +void DCD_DevConnect (USB_OTG_CORE_HANDLE *pdev) +{ +#ifndef USE_OTG_MODE + USB_OTG_DCTL_TypeDef dctl; + dctl.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCTL); + /* Connect device */ + dctl.b.sftdiscon = 0; + USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCTL, dctl.d32); + USB_OTG_BSP_mDelay(3); +#endif +} + + +/** +* @brief Disconnect device (disable internal pull-up) +* @param pdev: device instance +* @retval : None +*/ +void DCD_DevDisconnect (USB_OTG_CORE_HANDLE *pdev) +{ +#ifndef USE_OTG_MODE + USB_OTG_DCTL_TypeDef dctl; + dctl.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCTL); + /* Disconnect device for 3ms */ + dctl.b.sftdiscon = 1; + USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCTL, dctl.d32); + USB_OTG_BSP_mDelay(3); +#endif +} + + +/** +* @brief returns the EP Status +* @param pdev : Selected device +* epnum : endpoint address +* @retval : EP status +*/ + +uint32_t DCD_GetEPStatus(USB_OTG_CORE_HANDLE *pdev ,uint8_t epnum) +{ + USB_OTG_EP *ep; + uint32_t Status = 0; + + if ((0x80 & epnum) == 0x80) + { + ep = &pdev->dev.in_ep[epnum & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[epnum]; + } + + Status = USB_OTG_GetEPStatus(pdev ,ep); + + /* Return the current status */ + return Status; +} + +/** +* @brief Set the EP Status +* @param pdev : Selected device +* Status : new Status +* epnum : EP address +* @retval : None +*/ +void DCD_SetEPStatus (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum , uint32_t Status) +{ + USB_OTG_EP *ep; + + if ((0x80 & epnum) == 0x80) + { + ep = &pdev->dev.in_ep[epnum & 0x7F]; + } + else + { + ep = &pdev->dev.out_ep[epnum]; + } + + USB_OTG_SetEPStatus(pdev ,ep , Status); +} + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ +#endif + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/otg/usb_dcd.h b/stm32/usb_lib/otg/usb_dcd.h new file mode 100644 index 0000000..9a23dc6 --- /dev/null +++ b/stm32/usb_lib/otg/usb_dcd.h @@ -0,0 +1,158 @@ +/** + ****************************************************************************** + * @file usb_dcd.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Peripheral Driver Header 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __DCD_H__ +#define __DCD_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_core.h" + + +/** @addtogroup USB_OTG_DRIVER +* @{ +*/ + +/** @defgroup USB_DCD +* @brief This file is the +* @{ +*/ + + +/** @defgroup USB_DCD_Exported_Defines +* @{ +*/ +#define USB_OTG_EP_CONTROL 0 +#define USB_OTG_EP_ISOC 1 +#define USB_OTG_EP_BULK 2 +#define USB_OTG_EP_INT 3 +#define USB_OTG_EP_MASK 3 + +/* Device Status */ +#define USB_OTG_DEFAULT 1 +#define USB_OTG_ADDRESSED 2 +#define USB_OTG_CONFIGURED 3 +#define USB_OTG_SUSPENDED 4 + +/** +* @} +*/ + + +/** @defgroup USB_DCD_Exported_Types +* @{ +*/ +/******************************************************************************** +Data structure type +********************************************************************************/ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} +EP_DESCRIPTOR , *PEP_DESCRIPTOR; + +/** +* @} +*/ + + +/** @defgroup USB_DCD_Exported_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USB_DCD_Exported_Variables +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USB_DCD_Exported_FunctionsPrototype +* @{ +*/ +/******************************************************************************** +EXPORTED FUNCTION FROM THE USB-OTG LAYER +********************************************************************************/ +void DCD_Init(USB_OTG_CORE_HANDLE *pdev , + USB_OTG_CORE_ID_TypeDef coreID); + +void DCD_DevConnect (USB_OTG_CORE_HANDLE *pdev); +void DCD_DevDisconnect (USB_OTG_CORE_HANDLE *pdev); +void DCD_EP_SetAddress (USB_OTG_CORE_HANDLE *pdev, + uint8_t address); +uint32_t DCD_EP_Open(USB_OTG_CORE_HANDLE *pdev , + uint8_t ep_addr, + uint16_t ep_mps, + uint8_t ep_type); + +uint32_t DCD_EP_Close (USB_OTG_CORE_HANDLE *pdev, + uint8_t ep_addr); + + +uint32_t DCD_EP_PrepareRx ( USB_OTG_CORE_HANDLE *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t buf_len); + +uint32_t DCD_EP_Tx (USB_OTG_CORE_HANDLE *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint32_t buf_len); +uint32_t DCD_EP_Stall (USB_OTG_CORE_HANDLE *pdev, + uint8_t epnum); +uint32_t DCD_EP_ClrStall (USB_OTG_CORE_HANDLE *pdev, + uint8_t epnum); +uint32_t DCD_EP_Flush (USB_OTG_CORE_HANDLE *pdev, + uint8_t epnum); +uint32_t DCD_Handle_ISR(USB_OTG_CORE_HANDLE *pdev); + +uint32_t DCD_GetEPStatus(USB_OTG_CORE_HANDLE *pdev , + uint8_t epnum); + +void DCD_SetEPStatus (USB_OTG_CORE_HANDLE *pdev , + uint8_t epnum , + uint32_t Status); + +/** +* @} +*/ + + +#endif //__DCD_H__ + + +/** +* @} +*/ + +/** +* @} +*/ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_lib/otg/usb_dcd_int.c b/stm32/usb_lib/otg/usb_dcd_int.c new file mode 100644 index 0000000..82567eb --- /dev/null +++ b/stm32/usb_lib/otg/usb_dcd_int.c @@ -0,0 +1,889 @@ +/** + ****************************************************************************** + * @file usb_dcd_int.c + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Peripheral Device interrupt subroutines + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#include "usb_conf.h" +#ifdef USE_DEVICE_MODE +/* Includes ------------------------------------------------------------------*/ +#include "usb_dcd_int.h" +/** @addtogroup USB_OTG_DRIVER +* @{ +*/ + +/** @defgroup USB_DCD_INT +* @brief This file contains the interrupt subroutines for the Device mode. +* @{ +*/ + + +/** @defgroup USB_DCD_INT_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_INT_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + + +/** @defgroup USB_DCD_INT_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_INT_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USB_DCD_INT_Private_FunctionPrototypes +* @{ +*/ +/* static functions */ +static uint32_t DCD_ReadDevInEP (USB_OTG_CORE_HANDLE *pdev, uint8_t epnum); + +/* Interrupt Handlers */ +static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_HandleOutEP_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_HandleSof_ISR(USB_OTG_CORE_HANDLE *pdev); + +static uint32_t DCD_HandleRxStatusQueueLevel_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev , uint32_t epnum); + +static uint32_t DCD_HandleUsbReset_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_HandleEnumDone_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_HandleResume_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_HandleUSBSuspend_ISR(USB_OTG_CORE_HANDLE *pdev); + +static uint32_t DCD_IsoINIncomplete_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_IsoOUTIncomplete_ISR(USB_OTG_CORE_HANDLE *pdev); +#ifdef VBUS_SENSING_ENABLED +static uint32_t DCD_SessionRequest_ISR(USB_OTG_CORE_HANDLE *pdev); +static uint32_t DCD_OTG_ISR(USB_OTG_CORE_HANDLE *pdev); +#endif + +/** +* @} +*/ + + +/** @defgroup USB_DCD_INT_Private_Functions +* @{ +*/ + + +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED +/** +* @brief USBD_OTG_EP1OUT_ISR_Handler +* handles all USB Interrupts +* @param pdev: device instance +* @retval status +*/ +uint32_t USBD_OTG_EP1OUT_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) +{ + + USB_OTG_DOEPINTn_TypeDef doepint; + USB_OTG_DEPXFRSIZ_TypeDef deptsiz; + + doepint.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[1]->DOEPINT); + doepint.d32&= USB_OTG_READ_REG32(&pdev->regs.DREGS->DOUTEP1MSK); + + /* Transfer complete */ + if ( doepint.b.xfercompl ) + { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(1, xfercompl); + if (pdev->cfg.dma_enable == 1) + { + deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[1]->DOEPTSIZ)); + /*ToDo : handle more than one single MPS size packet */ + pdev->dev.out_ep[1].xfer_count = pdev->dev.out_ep[1].maxpacket - \ + deptsiz.b.xfersize; + } + /* Inform upper layer: data ready */ + /* RX COMPLETE */ + USBD_DCD_INT_fops->DataOutStage(pdev , 1); + + } + + /* Endpoint disable */ + if ( doepint.b.epdisabled ) + { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(1, epdisabled); + } + /* AHB Error */ + if ( doepint.b.ahberr ) + { + CLEAR_OUT_EP_INTR(1, ahberr); + } + return 1; +} + +/** +* @brief USBD_OTG_EP1IN_ISR_Handler +* handles all USB Interrupts +* @param pdev: device instance +* @retval status +*/ +uint32_t USBD_OTG_EP1IN_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) +{ + + USB_OTG_DIEPINTn_TypeDef diepint; + uint32_t fifoemptymsk, msk, emp; + + msk = USB_OTG_READ_REG32(&pdev->regs.DREGS->DINEP1MSK); + emp = USB_OTG_READ_REG32(&pdev->regs.DREGS->DIEPEMPMSK); + msk |= ((emp >> 1 ) & 0x1) << 7; + diepint.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[1]->DIEPINT) & msk; + + if ( diepint.b.xfercompl ) + { + fifoemptymsk = 0x1 << 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); + CLEAR_IN_EP_INTR(1, xfercompl); + /* TX COMPLETE */ + USBD_DCD_INT_fops->DataInStage(pdev , 1); + } + if ( diepint.b.ahberr ) + { + CLEAR_IN_EP_INTR(1, ahberr); + } + if ( diepint.b.epdisabled ) + { + CLEAR_IN_EP_INTR(1, epdisabled); + } + if ( diepint.b.timeout ) + { + CLEAR_IN_EP_INTR(1, timeout); + } + if (diepint.b.intktxfemp) + { + CLEAR_IN_EP_INTR(1, intktxfemp); + } + if (diepint.b.intknepmis) + { + CLEAR_IN_EP_INTR(1, intknepmis); + } + if (diepint.b.inepnakeff) + { + CLEAR_IN_EP_INTR(1, inepnakeff); + } + if (diepint.b.emptyintr) + { + DCD_WriteEmptyTxFifo(pdev , 1); + CLEAR_IN_EP_INTR(1, emptyintr); + } + return 1; +} +#endif + +/** +* @brief STM32_USBF_OTG_ISR_Handler +* handles all USB Interrupts +* @param pdev: device instance +* @retval status +*/ +uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintr_status; + uint32_t retval = 0; + + if (USB_OTG_IsDeviceMode(pdev)) /* ensure that we are in device mode */ + { + gintr_status.d32 = USB_OTG_ReadCoreItr(pdev); + if (!gintr_status.d32) /* avoid spurious interrupt */ + { + return 0; + } + + if (gintr_status.b.outepintr) + { + retval |= DCD_HandleOutEP_ISR(pdev); + } + + if (gintr_status.b.inepint) + { + retval |= DCD_HandleInEP_ISR(pdev); + } + + if (gintr_status.b.modemismatch) + { + USB_OTG_GINTSTS_TypeDef gintsts; + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.modemismatch = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); + } + + if (gintr_status.b.wkupintr) + { + retval |= DCD_HandleResume_ISR(pdev); + } + + if (gintr_status.b.usbsuspend) + { + retval |= DCD_HandleUSBSuspend_ISR(pdev); + } + if (gintr_status.b.sofintr) + { + retval |= DCD_HandleSof_ISR(pdev); + + } + + if (gintr_status.b.rxstsqlvl) + { + retval |= DCD_HandleRxStatusQueueLevel_ISR(pdev); + + } + + if (gintr_status.b.usbreset) + { + retval |= DCD_HandleUsbReset_ISR(pdev); + + } + if (gintr_status.b.enumdone) + { + retval |= DCD_HandleEnumDone_ISR(pdev); + } + + if (gintr_status.b.incomplisoin) + { + retval |= DCD_IsoINIncomplete_ISR(pdev); + } + + if (gintr_status.b.incomplisoout) + { + retval |= DCD_IsoOUTIncomplete_ISR(pdev); + } +#ifdef VBUS_SENSING_ENABLED + if (gintr_status.b.sessreqintr) + { + retval |= DCD_SessionRequest_ISR(pdev); + } + + if (gintr_status.b.otgintr) + { + retval |= DCD_OTG_ISR(pdev); + } +#endif + } + return retval; +} + +#ifdef VBUS_SENSING_ENABLED +/** +* @brief DCD_SessionRequest_ISR +* Indicates that the USB_OTG controller has detected a connection +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_SessionRequest_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + USBD_DCD_INT_fops->DevConnected (pdev); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.sessreqintr = 1; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); + return 1; +} + +/** +* @brief DCD_OTG_ISR +* Indicates that the USB_OTG controller has detected an OTG event: +* used to detect the end of session i.e. disconnection +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_OTG_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + + USB_OTG_GOTGINT_TypeDef gotgint; + + gotgint.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GOTGINT); + + if (gotgint.b.sesenddet) + { + USBD_DCD_INT_fops->DevDisconnected (pdev); + } + /* Clear OTG interrupt */ + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GOTGINT, gotgint.d32); + return 1; +} +#endif +/** +* @brief DCD_HandleResume_ISR +* Indicates that the USB_OTG controller has detected a resume or +* remote Wake-up sequence +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleResume_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + USB_OTG_DCTL_TypeDef devctl; + USB_OTG_PCGCCTL_TypeDef power; + + 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); + } + + /* Clear the Remote Wake-up Signaling */ + devctl.d32 = 0; + devctl.b.rmtwkupsig = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, devctl.d32, 0); + + /* Inform upper layer by the Resume Event */ + USBD_DCD_INT_fops->Resume (pdev); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.wkupintr = 1; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); + return 1; +} + +/** +* @brief USB_OTG_HandleUSBSuspend_ISR +* Indicates that SUSPEND state has been detected on the USB +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleUSBSuspend_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + USB_OTG_PCGCCTL_TypeDef power; + USB_OTG_DSTS_TypeDef dsts; + + USBD_DCD_INT_fops->Suspend (pdev); + + dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbsuspend = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); + + if((pdev->cfg.low_power) && (dsts.b.suspsts == 1)) + { + /* switch-off the clocks */ + power.d32 = 0; + power.b.stoppclk = 1; + USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); + + power.b.gatehclk = 1; + USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, 0, power.d32); + + /* Request to enter Sleep mode after exit from current ISR */ + SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk); + } + return 1; +} + +/** +* @brief DCD_HandleInEP_ISR +* Indicates that an IN EP has a pending Interrupt +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_DIEPINTn_TypeDef diepint; + + uint32_t ep_intr; + uint32_t epnum = 0; + uint32_t fifoemptymsk; + diepint.d32 = 0; + ep_intr = USB_OTG_ReadDevAllInEPItr(pdev); + + while ( ep_intr ) + { + if (ep_intr&0x1) /* In ITR */ + { + diepint.d32 = DCD_ReadDevInEP(pdev , epnum); /* Get In ITR status */ + if ( diepint.b.xfercompl ) + { + fifoemptymsk = 0x1 << epnum; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); + CLEAR_IN_EP_INTR(epnum, xfercompl); + /* TX COMPLETE */ + USBD_DCD_INT_fops->DataInStage(pdev , epnum); + + if (pdev->cfg.dma_enable == 1) + { + if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_IN)) + { + /* prepare to rx more setup packets */ + USB_OTG_EP0_OutStart(pdev); + } + } + } + if ( diepint.b.ahberr ) + { + CLEAR_IN_EP_INTR(epnum, ahberr); + } + if ( diepint.b.timeout ) + { + CLEAR_IN_EP_INTR(epnum, timeout); + } + if (diepint.b.intktxfemp) + { + CLEAR_IN_EP_INTR(epnum, intktxfemp); + } + if (diepint.b.intknepmis) + { + CLEAR_IN_EP_INTR(epnum, intknepmis); + } + if (diepint.b.inepnakeff) + { + CLEAR_IN_EP_INTR(epnum, inepnakeff); + } + if ( diepint.b.epdisabled ) + { + CLEAR_IN_EP_INTR(epnum, epdisabled); + } + if (diepint.b.emptyintr) + { + + DCD_WriteEmptyTxFifo(pdev , epnum); + + CLEAR_IN_EP_INTR(epnum, emptyintr); + } + } + epnum++; + ep_intr >>= 1; + } + + return 1; +} + +/** +* @brief DCD_HandleOutEP_ISR +* Indicates that an OUT EP has a pending Interrupt +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleOutEP_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + uint32_t ep_intr; + USB_OTG_DOEPINTn_TypeDef doepint; + USB_OTG_DEPXFRSIZ_TypeDef deptsiz; + uint32_t epnum = 0; + + doepint.d32 = 0; + + /* Read in the device interrupt bits */ + ep_intr = USB_OTG_ReadDevAllOutEp_itr(pdev); + + while ( ep_intr ) + { + if (ep_intr&0x1) + { + + doepint.d32 = USB_OTG_ReadDevOutEP_itr(pdev, epnum); + + /* Transfer complete */ + if ( doepint.b.xfercompl ) + { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(epnum, xfercompl); + if (pdev->cfg.dma_enable == 1) + { + deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[epnum]->DOEPTSIZ)); + /*ToDo : handle more than one single MPS size packet */ + pdev->dev.out_ep[epnum].xfer_count = pdev->dev.out_ep[epnum].maxpacket - \ + deptsiz.b.xfersize; + } + /* Inform upper layer: data ready */ + /* RX COMPLETE */ + USBD_DCD_INT_fops->DataOutStage(pdev , epnum); + + if (pdev->cfg.dma_enable == 1) + { + if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_OUT)) + { + /* prepare to rx more setup packets */ + USB_OTG_EP0_OutStart(pdev); + } + } + } + /* Endpoint disable */ + if ( doepint.b.epdisabled ) + { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(epnum, epdisabled); + } + /* AHB Error */ + if ( doepint.b.ahberr ) + { + CLEAR_OUT_EP_INTR(epnum, ahberr); + } + /* Setup Phase Done (control EPs) */ + if ( doepint.b.setup ) + { + + /* inform the upper layer that a setup packet is available */ + /* SETUP COMPLETE */ + USBD_DCD_INT_fops->SetupStage(pdev); + CLEAR_OUT_EP_INTR(epnum, setup); + } + } + epnum++; + ep_intr >>= 1; + } + return 1; +} + +/** +* @brief DCD_HandleSof_ISR +* Handles the SOF Interrupts +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleSof_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef GINTSTS; + + + USBD_DCD_INT_fops->SOF(pdev); + + /* Clear interrupt */ + GINTSTS.d32 = 0; + GINTSTS.b.sofintr = 1; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, GINTSTS.d32); + + return 1; +} + +/** +* @brief DCD_HandleRxStatusQueueLevel_ISR +* Handles the Rx Status Queue Level Interrupt +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleRxStatusQueueLevel_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTMSK_TypeDef int_mask; + USB_OTG_DRXSTS_TypeDef status; + USB_OTG_EP *ep; + + /* Disable the Rx Status Queue Level interrupt */ + int_mask.d32 = 0; + int_mask.b.rxstsqlvl = 1; + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, int_mask.d32, 0); + + /* Get the Status from the top of the FIFO */ + status.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRXSTSP ); + + ep = &pdev->dev.out_ep[status.b.epnum]; + + switch (status.b.pktsts) + { + case STS_GOUT_NAK: + break; + case STS_DATA_UPDT: + if (status.b.bcnt) + { + USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt); + ep->xfer_buff += status.b.bcnt; + ep->xfer_count += status.b.bcnt; + } + break; + case STS_XFER_COMP: + break; + case STS_SETUP_COMP: + break; + case STS_SETUP_UPDT: + /* Copy the setup packet received in FIFO into the setup buffer in RAM */ + USB_OTG_ReadPacket(pdev , pdev->dev.setup_packet, 8); + ep->xfer_count += status.b.bcnt; + break; + default: + break; + } + + /* Enable the Rx Status Queue Level interrupt */ + USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, int_mask.d32); + + return 1; +} + +/** +* @brief DCD_WriteEmptyTxFifo +* check FIFO for the next packet to be loaded +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum) +{ + USB_OTG_DTXFSTSn_TypeDef txstatus; + USB_OTG_EP *ep; + uint32_t len = 0; + uint32_t len32b; + txstatus.d32 = 0; + + ep = &pdev->dev.in_ep[epnum]; + + len = ep->xfer_len - ep->xfer_count; + + if (len > ep->maxpacket) + { + len = ep->maxpacket; + } + + len32b = (len + 3) / 4; + txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS); + + + + while (txstatus.b.txfspcavail > len32b && + ep->xfer_count < ep->xfer_len && + ep->xfer_len != 0) + { + /* Write the FIFO */ + len = ep->xfer_len - ep->xfer_count; + + if (len > ep->maxpacket) + { + len = ep->maxpacket; + } + len32b = (len + 3) / 4; + + USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len); + + ep->xfer_buff += len; + ep->xfer_count += len; + + txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS); + } + + return 1; +} + +/** +* @brief DCD_HandleUsbReset_ISR +* This interrupt occurs when a USB Reset is detected +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleUsbReset_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_DAINT_TypeDef daintmsk; + USB_OTG_DOEPMSK_TypeDef doepmsk; + USB_OTG_DIEPMSK_TypeDef diepmsk; + USB_OTG_DCFG_TypeDef dcfg; + USB_OTG_DCTL_TypeDef dctl; + USB_OTG_GINTSTS_TypeDef gintsts; + uint32_t i; + + dctl.d32 = 0; + daintmsk.d32 = 0; + doepmsk.d32 = 0; + diepmsk.d32 = 0; + dcfg.d32 = 0; + gintsts.d32 = 0; + + /* Clear the Remote Wake-up Signaling */ + dctl.b.rmtwkupsig = 1; + USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, 0 ); + + /* Flush the Tx FIFO */ + USB_OTG_FlushTxFifo(pdev , 0 ); + + 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->DAINT, 0xFFFFFFFF ); + + daintmsk.ep.in = 1; + daintmsk.ep.out = 1; + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, daintmsk.d32 ); + + doepmsk.b.setup = 1; + doepmsk.b.xfercompl = 1; + doepmsk.b.ahberr = 1; + doepmsk.b.epdisabled = 1; + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, doepmsk.d32 ); +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOUTEP1MSK, doepmsk.d32 ); +#endif + diepmsk.b.xfercompl = 1; + diepmsk.b.timeout = 1; + diepmsk.b.epdisabled = 1; + diepmsk.b.ahberr = 1; + diepmsk.b.intknepmis = 1; + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, diepmsk.d32 ); +#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DINEP1MSK, diepmsk.d32 ); +#endif + /* Reset Device Address */ + dcfg.d32 = USB_OTG_READ_REG32( &pdev->regs.DREGS->DCFG); + dcfg.b.devaddr = 0; + USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DCFG, dcfg.d32); + + + /* setup EP0 to receive SETUP packets */ + USB_OTG_EP0_OutStart(pdev); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbreset = 1; + USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); + + /*Reset internal state machine */ + USBD_DCD_INT_fops->Reset(pdev); + return 1; +} + +/** +* @brief DCD_HandleEnumDone_ISR +* Read the device status register and set the device speed +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_HandleEnumDone_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + USB_OTG_GUSBCFG_TypeDef gusbcfg; + + USB_OTG_EP0Activate(pdev); + + /* Set USB turn-around time based on device speed and PHY interface. */ + gusbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); + + /* Full or High speed */ + if ( USB_OTG_GetDeviceSpeed(pdev) == USB_SPEED_HIGH) + { + pdev->cfg.speed = USB_OTG_SPEED_HIGH; + pdev->cfg.mps = USB_OTG_HS_MAX_PACKET_SIZE ; + gusbcfg.b.usbtrdtim = 9; + } + else + { + pdev->cfg.speed = USB_OTG_SPEED_FULL; + pdev->cfg.mps = USB_OTG_FS_MAX_PACKET_SIZE ; + gusbcfg.b.usbtrdtim = 5; + } + + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, gusbcfg.d32); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.enumdone = 1; + USB_OTG_WRITE_REG32( &pdev->regs.GREGS->GINTSTS, gintsts.d32 ); + return 1; +} + + +/** +* @brief DCD_IsoINIncomplete_ISR +* handle the ISO IN incomplete interrupt +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_IsoINIncomplete_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + + gintsts.d32 = 0; + + USBD_DCD_INT_fops->IsoINIncomplete (pdev); + + /* Clear interrupt */ + gintsts.b.incomplisoin = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); + + return 1; +} + +/** +* @brief DCD_IsoOUTIncomplete_ISR +* handle the ISO OUT incomplete interrupt +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_IsoOUTIncomplete_ISR(USB_OTG_CORE_HANDLE *pdev) +{ + USB_OTG_GINTSTS_TypeDef gintsts; + + gintsts.d32 = 0; + + USBD_DCD_INT_fops->IsoOUTIncomplete (pdev); + + /* Clear interrupt */ + gintsts.b.incomplisoout = 1; + USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); + return 1; +} +/** +* @brief DCD_ReadDevInEP +* Reads ep flags +* @param pdev: device instance +* @retval status +*/ +static uint32_t DCD_ReadDevInEP (USB_OTG_CORE_HANDLE *pdev, uint8_t epnum) +{ + uint32_t v, msk, emp; + msk = USB_OTG_READ_REG32(&pdev->regs.DREGS->DIEPMSK); + emp = USB_OTG_READ_REG32(&pdev->regs.DREGS->DIEPEMPMSK); + msk |= ((emp >> epnum) & 0x1) << 7; + v = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DIEPINT) & msk; + return v; +} + + + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ +#endif + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/stm32/usb_lib/otg/usb_dcd_int.h b/stm32/usb_lib/otg/usb_dcd_int.h new file mode 100644 index 0000000..3cbebd8 --- /dev/null +++ b/stm32/usb_lib/otg/usb_dcd_int.h @@ -0,0 +1,121 @@ +/** + ****************************************************************************** + * @file usb_dcd_int.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief Peripheral Device Interface 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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef USB_DCD_INT_H__ +#define USB_DCD_INT_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_dcd.h" + + + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_DCD_INT + * @brief This file is the + * @{ + */ + + +/** @defgroup USB_DCD_INT_Exported_Defines + * @{ + */ + +typedef struct _USBD_DCD_INT +{ + uint8_t (* DataOutStage) (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); + uint8_t (* DataInStage) (USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); + uint8_t (* SetupStage) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* SOF) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* Reset) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* Suspend) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* Resume) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* IsoINIncomplete) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* IsoOUTIncomplete) (USB_OTG_CORE_HANDLE *pdev); + + uint8_t (* DevConnected) (USB_OTG_CORE_HANDLE *pdev); + uint8_t (* DevDisconnected) (USB_OTG_CORE_HANDLE *pdev); + +}USBD_DCD_INT_cb_TypeDef; + +extern USBD_DCD_INT_cb_TypeDef *USBD_DCD_INT_fops; +/** + * @} + */ + + +/** @defgroup USB_DCD_INT_Exported_Types + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_DCD_INT_Exported_Macros + * @{ + */ + +#define CLEAR_IN_EP_INTR(epnum,intr) \ + diepint.d32=0; \ + diepint.b.intr = 1; \ + USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[epnum]->DIEPINT,diepint.d32); + +#define CLEAR_OUT_EP_INTR(epnum,intr) \ + doepint.d32=0; \ + doepint.b.intr = 1; \ + USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[epnum]->DOEPINT,doepint.d32); + +/** + * @} + */ + +/** @defgroup USB_DCD_INT_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_DCD_INT_Exported_FunctionsPrototype + * @{ + */ + +uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev); + +/** + * @} + */ + + +#endif // USB_DCD_INT_H__ + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_lib/otg/usb_defines.h b/stm32/usb_lib/otg/usb_defines.h new file mode 100644 index 0000000..70f9952 --- /dev/null +++ b/stm32/usb_lib/otg/usb_defines.h @@ -0,0 +1,244 @@ +/** + ****************************************************************************** + * @file usb_defines.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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DEF_H__ +#define __USB_DEF_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_DEFINES + * @brief This file is the + * @{ + */ + + +/** @defgroup USB_DEFINES_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup _CORE_DEFINES_ + * @{ + */ + +#define USB_OTG_SPEED_PARAM_HIGH 0 +#define USB_OTG_SPEED_PARAM_HIGH_IN_FULL 1 +#define USB_OTG_SPEED_PARAM_FULL 3 + +#define USB_OTG_SPEED_HIGH 0 +#define USB_OTG_SPEED_FULL 1 + +#define USB_OTG_ULPI_PHY 1 +#define USB_OTG_EMBEDDED_PHY 2 +#define USB_OTG_I2C_PHY 3 + +/** + * @} + */ + + +/** @defgroup _GLOBAL_DEFINES_ + * @{ + */ +#define GAHBCFG_TXFEMPTYLVL_EMPTY 1 +#define GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 +#define GAHBCFG_GLBINT_ENABLE 1 +#define GAHBCFG_INT_DMA_BURST_SINGLE 0 +#define GAHBCFG_INT_DMA_BURST_INCR 1 +#define GAHBCFG_INT_DMA_BURST_INCR4 3 +#define GAHBCFG_INT_DMA_BURST_INCR8 5 +#define GAHBCFG_INT_DMA_BURST_INCR16 7 +#define GAHBCFG_DMAENABLE 1 +#define GAHBCFG_TXFEMPTYLVL_EMPTY 1 +#define GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 +#define GRXSTS_PKTSTS_IN 2 +#define GRXSTS_PKTSTS_IN_XFER_COMP 3 +#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR 5 +#define GRXSTS_PKTSTS_CH_HALTED 7 +/** + * @} + */ + + +/** @defgroup _OnTheGo_DEFINES_ + * @{ + */ +#define MODE_HNP_SRP_CAPABLE 0 +#define MODE_SRP_ONLY_CAPABLE 1 +#define MODE_NO_HNP_SRP_CAPABLE 2 +#define MODE_SRP_CAPABLE_DEVICE 3 +#define MODE_NO_SRP_CAPABLE_DEVICE 4 +#define MODE_SRP_CAPABLE_HOST 5 +#define MODE_NO_SRP_CAPABLE_HOST 6 +#define A_HOST 1 +#define A_SUSPEND 2 +#define A_PERIPHERAL 3 +#define B_PERIPHERAL 4 +#define B_HOST 5 +#define DEVICE_MODE 0 +#define HOST_MODE 1 +#define OTG_MODE 2 +/** + * @} + */ + + +/** @defgroup __DEVICE_DEFINES_ + * @{ + */ +#define DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 +#define DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 +#define DSTS_ENUMSPD_LS_PHY_6MHZ 2 +#define DSTS_ENUMSPD_FS_PHY_48MHZ 3 + +#define DCFG_FRAME_INTERVAL_80 0 +#define DCFG_FRAME_INTERVAL_85 1 +#define DCFG_FRAME_INTERVAL_90 2 +#define DCFG_FRAME_INTERVAL_95 3 + +#define DEP0CTL_MPS_64 0 +#define DEP0CTL_MPS_32 1 +#define DEP0CTL_MPS_16 2 +#define DEP0CTL_MPS_8 3 + +#define EP_SPEED_LOW 0 +#define EP_SPEED_FULL 1 +#define EP_SPEED_HIGH 2 + +#define EP_TYPE_CTRL 0 +#define EP_TYPE_ISOC 1 +#define EP_TYPE_BULK 2 +#define EP_TYPE_INTR 3 +#define EP_TYPE_MSK 3 + +#define STS_GOUT_NAK 1 +#define STS_DATA_UPDT 2 +#define STS_XFER_COMP 3 +#define STS_SETUP_COMP 4 +#define STS_SETUP_UPDT 6 +/** + * @} + */ + + +/** @defgroup __HOST_DEFINES_ + * @{ + */ +#define HC_PID_DATA0 0 +#define HC_PID_DATA2 1 +#define HC_PID_DATA1 2 +#define HC_PID_SETUP 3 + +#define HPRT0_PRTSPD_HIGH_SPEED 0 +#define HPRT0_PRTSPD_FULL_SPEED 1 +#define HPRT0_PRTSPD_LOW_SPEED 2 + +#define HCFG_30_60_MHZ 0 +#define HCFG_48_MHZ 1 +#define HCFG_6_MHZ 2 + +#define HCCHAR_CTRL 0 +#define HCCHAR_ISOC 1 +#define HCCHAR_BULK 2 +#define HCCHAR_INTR 3 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/** + * @} + */ + + +/** @defgroup USB_DEFINES_Exported_Types + * @{ + */ + +typedef enum +{ + USB_OTG_HS_CORE_ID = 0, + USB_OTG_FS_CORE_ID = 1 +}USB_OTG_CORE_ID_TypeDef; +/** + * @} + */ + + +/** @defgroup USB_DEFINES_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_DEFINES_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_DEFINES_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + + +/** @defgroup Internal_Macro's + * @{ + */ +#define USB_OTG_READ_REG32(reg) (*(__IO uint32_t *)reg) +#define USB_OTG_WRITE_REG32(reg,value) (*(__IO uint32_t *)reg = value) +#define USB_OTG_MODIFY_REG32(reg,clear_mask,set_mask) \ + USB_OTG_WRITE_REG32(reg, (((USB_OTG_READ_REG32(reg)) & ~clear_mask) | set_mask ) ) + +/******************************************************************************** + ENUMERATION TYPE +********************************************************************************/ +enum USB_OTG_SPEED { + USB_SPEED_UNKNOWN = 0, + USB_SPEED_LOW, + USB_SPEED_FULL, + USB_SPEED_HIGH +}; + +#endif //__USB_DEFINES__H__ + + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + diff --git a/stm32/usb_lib/otg/usb_regs.h b/stm32/usb_lib/otg/usb_regs.h new file mode 100644 index 0000000..57e478c --- /dev/null +++ b/stm32/usb_lib/otg/usb_regs.h @@ -0,0 +1,1206 @@ +/** + ****************************************************************************** + * @file usb_regs.h + * @author MCD Application Team + * @version V2.0.0 + * @date 22-July-2011 + * @brief hardware registers + ****************************************************************************** + * @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. + * + * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_OTG_REGS_H__ +#define __USB_OTG_REGS_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + + +/** @addtogroup USB_OTG_DRIVER + * @{ + */ + +/** @defgroup USB_REGS + * @brief This file is the + * @{ + */ + + +/** @defgroup USB_REGS_Exported_Defines + * @{ + */ + +#define USB_OTG_HS_BASE_ADDR 0x40040000 +#define USB_OTG_FS_BASE_ADDR 0x50000000 + +#define USB_OTG_CORE_GLOBAL_REGS_OFFSET 0x000 +#define USB_OTG_DEV_GLOBAL_REG_OFFSET 0x800 +#define USB_OTG_DEV_IN_EP_REG_OFFSET 0x900 +#define USB_OTG_EP_REG_OFFSET 0x20 +#define USB_OTG_DEV_OUT_EP_REG_OFFSET 0xB00 +#define USB_OTG_HOST_GLOBAL_REG_OFFSET 0x400 +#define USB_OTG_HOST_PORT_REGS_OFFSET 0x440 +#define USB_OTG_HOST_CHAN_REGS_OFFSET 0x500 +#define USB_OTG_CHAN_REGS_OFFSET 0x20 +#define USB_OTG_PCGCCTL_OFFSET 0xE00 +#define USB_OTG_DATA_FIFO_OFFSET 0x1000 +#define USB_OTG_DATA_FIFO_SIZE 0x1000 + + +#define USB_OTG_MAX_TX_FIFOS 15 + +#define USB_OTG_HS_MAX_PACKET_SIZE 512 +#define USB_OTG_FS_MAX_PACKET_SIZE 64 +#define USB_OTG_MAX_EP0_SIZE 64 +/** + * @} + */ + +/** @defgroup USB_REGS_Exported_Types + * @{ + */ + +/** @defgroup __USB_OTG_Core_register + * @{ + */ +typedef struct _USB_OTG_GREGS //000h +{ + __IO uint32_t GOTGCTL; /* USB_OTG Control and Status Register 000h*/ + __IO uint32_t GOTGINT; /* USB_OTG Interrupt Register 004h*/ + __IO uint32_t GAHBCFG; /* Core AHB Configuration Register 008h*/ + __IO uint32_t GUSBCFG; /* Core USB Configuration Register 00Ch*/ + __IO uint32_t GRSTCTL; /* Core Reset Register 010h*/ + __IO uint32_t GINTSTS; /* Core Interrupt Register 014h*/ + __IO uint32_t GINTMSK; /* Core Interrupt Mask Register 018h*/ + __IO uint32_t GRXSTSR; /* Receive Sts Q Read Register 01Ch*/ + __IO uint32_t GRXSTSP; /* Receive Sts Q Read & POP Register 020h*/ + __IO uint32_t GRXFSIZ; /* Receive FIFO Size Register 024h*/ + __IO uint32_t DIEPTXF0_HNPTXFSIZ; /* EP0 / Non Periodic Tx FIFO Size Register 028h*/ + __IO uint32_t HNPTXSTS; /* Non Periodic Tx FIFO/Queue Sts reg 02Ch*/ + __IO uint32_t GI2CCTL; /* I2C Access Register 030h*/ + uint32_t Reserved34; /* PHY Vendor Control Register 034h*/ + __IO uint32_t GCCFG; /* General Purpose IO Register 038h*/ + __IO uint32_t CID; /* User ID Register 03Ch*/ + uint32_t Reserved40[48]; /* Reserved 040h-0FFh*/ + __IO uint32_t HPTXFSIZ; /* Host Periodic Tx FIFO Size Reg 100h*/ + __IO uint32_t DIEPTXF[USB_OTG_MAX_TX_FIFOS];/* dev Periodic Transmit FIFO */ +} +USB_OTG_GREGS; +/** + * @} + */ + + +/** @defgroup __device_Registers + * @{ + */ +typedef struct _USB_OTG_DREGS // 800h +{ + __IO uint32_t DCFG; /* dev Configuration Register 800h*/ + __IO uint32_t DCTL; /* dev Control Register 804h*/ + __IO uint32_t DSTS; /* dev Status Register (RO) 808h*/ + uint32_t Reserved0C; /* Reserved 80Ch*/ + __IO uint32_t DIEPMSK; /* dev IN Endpoint Mask 810h*/ + __IO uint32_t DOEPMSK; /* dev OUT Endpoint Mask 814h*/ + __IO uint32_t DAINT; /* dev All Endpoints Itr Reg 818h*/ + __IO uint32_t DAINTMSK; /* dev All Endpoints Itr Mask 81Ch*/ + uint32_t Reserved20; /* Reserved 820h*/ + uint32_t Reserved9; /* Reserved 824h*/ + __IO uint32_t DVBUSDIS; /* dev VBUS discharge Register 828h*/ + __IO uint32_t DVBUSPULSE; /* dev VBUS Pulse Register 82Ch*/ + __IO uint32_t DTHRCTL; /* dev thr 830h*/ + __IO uint32_t DIEPEMPMSK; /* dev empty msk 834h*/ + __IO uint32_t DEACHINT; /* dedicated EP interrupt 838h*/ + __IO uint32_t DEACHMSK; /* dedicated EP msk 83Ch*/ + uint32_t Reserved40; /* dedicated EP mask 840h*/ + __IO uint32_t DINEP1MSK; /* dedicated EP mask 844h*/ + uint32_t Reserved44[15]; /* Reserved 844-87Ch*/ + __IO uint32_t DOUTEP1MSK; /* dedicated EP msk 884h*/ +} +USB_OTG_DREGS; +/** + * @} + */ + + +/** @defgroup __IN_Endpoint-Specific_Register + * @{ + */ +typedef struct _USB_OTG_INEPREGS +{ + __IO uint32_t DIEPCTL; /* dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h*/ + uint32_t Reserved04; /* Reserved 900h + (ep_num * 20h) + 04h*/ + __IO uint32_t DIEPINT; /* dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h*/ + uint32_t Reserved0C; /* Reserved 900h + (ep_num * 20h) + 0Ch*/ + __IO uint32_t DIEPTSIZ; /* IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h*/ + __IO uint32_t DIEPDMA; /* IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h*/ + __IO uint32_t DTXFSTS;/*IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h*/ + uint32_t Reserved18; /* Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch*/ +} +USB_OTG_INEPREGS; +/** + * @} + */ + + +/** @defgroup __OUT_Endpoint-Specific_Registers + * @{ + */ +typedef struct _USB_OTG_OUTEPREGS +{ + __IO uint32_t DOEPCTL; /* dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h*/ + __IO uint32_t DOUTEPFRM; /* dev OUT Endpoint Frame number B00h + (ep_num * 20h) + 04h*/ + __IO uint32_t DOEPINT; /* dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h*/ + uint32_t Reserved0C; /* Reserved B00h + (ep_num * 20h) + 0Ch*/ + __IO uint32_t DOEPTSIZ; /* dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h*/ + __IO uint32_t DOEPDMA; /* dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h*/ + uint32_t Reserved18[2]; /* Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch*/ +} +USB_OTG_OUTEPREGS; +/** + * @} + */ + + +/** @defgroup __Host_Mode_Register_Structures + * @{ + */ +typedef struct _USB_OTG_HREGS +{ + __IO uint32_t HCFG; /* Host Configuration Register 400h*/ + __IO uint32_t HFIR; /* Host Frame Interval Register 404h*/ + __IO uint32_t HFNUM; /* Host Frame Nbr/Frame Remaining 408h*/ + uint32_t Reserved40C; /* Reserved 40Ch*/ + __IO uint32_t HPTXSTS; /* Host Periodic Tx FIFO/ Queue Status 410h*/ + __IO uint32_t HAINT; /* Host All Channels Interrupt Register 414h*/ + __IO uint32_t HAINTMSK; /* Host All Channels Interrupt Mask 418h*/ +} +USB_OTG_HREGS; +/** + * @} + */ + + +/** @defgroup __Host_Channel_Specific_Registers + * @{ + */ +typedef struct _USB_OTG_HC_REGS +{ + __IO uint32_t HCCHAR; + __IO uint32_t HCSPLT; + __IO uint32_t HCINT; + __IO uint32_t HCGINTMSK; + __IO uint32_t HCTSIZ; + __IO uint32_t HCDMA; + uint32_t Reserved[2]; +} +USB_OTG_HC_REGS; +/** + * @} + */ + + +/** @defgroup __otg_Core_registers + * @{ + */ +typedef struct USB_OTG_core_regs //000h +{ + USB_OTG_GREGS *GREGS; + USB_OTG_DREGS *DREGS; + USB_OTG_HREGS *HREGS; + USB_OTG_INEPREGS *INEP_REGS[USB_OTG_MAX_TX_FIFOS]; + USB_OTG_OUTEPREGS *OUTEP_REGS[USB_OTG_MAX_TX_FIFOS]; + USB_OTG_HC_REGS *HC_REGS[USB_OTG_MAX_TX_FIFOS]; + __IO uint32_t *HPRT0; + __IO uint32_t *DFIFO[USB_OTG_MAX_TX_FIFOS]; + __IO uint32_t *PCGCCTL; +} +USB_OTG_CORE_REGS , *PUSB_OTG_CORE_REGS; +typedef union _USB_OTG_OTGCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t sesreqscs : + 1; +uint32_t sesreq : + 1; +uint32_t Reserved2_7 : + 6; +uint32_t hstnegscs : + 1; +uint32_t hnpreq : + 1; +uint32_t hstsethnpen : + 1; +uint32_t devhnpen : + 1; +uint32_t Reserved12_15 : + 4; +uint32_t conidsts : + 1; +uint32_t Reserved17 : + 1; +uint32_t asesvld : + 1; +uint32_t bsesvld : + 1; +uint32_t currmod : + 1; +uint32_t Reserved21_31 : + 11; + } + b; +} USB_OTG_OTGCTL_TypeDef ; +typedef union _USB_OTG_GOTGINT_TypeDef +{ + uint32_t d32; + struct + { +uint32_t Reserved0_1 : + 2; +uint32_t sesenddet : + 1; +uint32_t Reserved3_7 : + 5; +uint32_t sesreqsucstschng : + 1; +uint32_t hstnegsucstschng : + 1; +uint32_t reserver10_16 : + 7; +uint32_t hstnegdet : + 1; +uint32_t adevtoutchng : + 1; +uint32_t debdone : + 1; +uint32_t Reserved31_20 : + 12; + } + b; +} USB_OTG_GOTGINT_TypeDef ; +typedef union _USB_OTG_GAHBCFG_TypeDef +{ + uint32_t d32; + struct + { +uint32_t glblintrmsk : + 1; +uint32_t hburstlen : + 4; +uint32_t dmaenable : + 1; +uint32_t Reserved : + 1; +uint32_t nptxfemplvl_txfemplvl : + 1; +uint32_t ptxfemplvl : + 1; +uint32_t Reserved9_31 : + 23; + } + b; +} USB_OTG_GAHBCFG_TypeDef ; +typedef union _USB_OTG_GUSBCFG_TypeDef +{ + uint32_t d32; + struct + { +uint32_t toutcal : + 3; +uint32_t phyif : + 1; +uint32_t ulpi_utmi_sel : + 1; +uint32_t fsintf : + 1; +uint32_t physel : + 1; +uint32_t ddrsel : + 1; +uint32_t srpcap : + 1; +uint32_t hnpcap : + 1; +uint32_t usbtrdtim : + 4; +uint32_t nptxfrwnden : + 1; +uint32_t phylpwrclksel : + 1; +uint32_t otgutmifssel : + 1; +uint32_t ulpi_fsls : + 1; +uint32_t ulpi_auto_res : + 1; +uint32_t ulpi_clk_sus_m : + 1; +uint32_t ulpi_ext_vbus_drv : + 1; +uint32_t ulpi_int_vbus_indicator : + 1; +uint32_t term_sel_dl_pulse : + 1; +uint32_t Reserved : + 6; +uint32_t force_host : + 1; +uint32_t force_dev : + 1; +uint32_t corrupt_tx : + 1; + } + b; +} USB_OTG_GUSBCFG_TypeDef ; +typedef union _USB_OTG_GRSTCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t csftrst : + 1; +uint32_t hsftrst : + 1; +uint32_t hstfrm : + 1; +uint32_t intknqflsh : + 1; +uint32_t rxfflsh : + 1; +uint32_t txfflsh : + 1; +uint32_t txfnum : + 5; +uint32_t Reserved11_29 : + 19; +uint32_t dmareq : + 1; +uint32_t ahbidle : + 1; + } + b; +} USB_OTG_GRSTCTL_TypeDef ; +typedef union _USB_OTG_GINTMSK_TypeDef +{ + uint32_t d32; + struct + { +uint32_t Reserved0 : + 1; +uint32_t modemismatch : + 1; +uint32_t otgintr : + 1; +uint32_t sofintr : + 1; +uint32_t rxstsqlvl : + 1; +uint32_t nptxfempty : + 1; +uint32_t ginnakeff : + 1; +uint32_t goutnakeff : + 1; +uint32_t Reserved8 : + 1; +uint32_t i2cintr : + 1; +uint32_t erlysuspend : + 1; +uint32_t usbsuspend : + 1; +uint32_t usbreset : + 1; +uint32_t enumdone : + 1; +uint32_t isooutdrop : + 1; +uint32_t eopframe : + 1; +uint32_t Reserved16 : + 1; +uint32_t epmismatch : + 1; +uint32_t inepintr : + 1; +uint32_t outepintr : + 1; +uint32_t incomplisoin : + 1; +uint32_t incomplisoout : + 1; +uint32_t Reserved22_23 : + 2; +uint32_t portintr : + 1; +uint32_t hcintr : + 1; +uint32_t ptxfempty : + 1; +uint32_t Reserved27 : + 1; +uint32_t conidstschng : + 1; +uint32_t disconnect : + 1; +uint32_t sessreqintr : + 1; +uint32_t wkupintr : + 1; + } + b; +} USB_OTG_GINTMSK_TypeDef ; +typedef union _USB_OTG_GINTSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t curmode : + 1; +uint32_t modemismatch : + 1; +uint32_t otgintr : + 1; +uint32_t sofintr : + 1; +uint32_t rxstsqlvl : + 1; +uint32_t nptxfempty : + 1; +uint32_t ginnakeff : + 1; +uint32_t goutnakeff : + 1; +uint32_t Reserved8 : + 1; +uint32_t i2cintr : + 1; +uint32_t erlysuspend : + 1; +uint32_t usbsuspend : + 1; +uint32_t usbreset : + 1; +uint32_t enumdone : + 1; +uint32_t isooutdrop : + 1; +uint32_t eopframe : + 1; +uint32_t intimerrx : + 1; +uint32_t epmismatch : + 1; +uint32_t inepint: + 1; +uint32_t outepintr : + 1; +uint32_t incomplisoin : + 1; +uint32_t incomplisoout : + 1; +uint32_t Reserved22_23 : + 2; +uint32_t portintr : + 1; +uint32_t hcintr : + 1; +uint32_t ptxfempty : + 1; +uint32_t Reserved27 : + 1; +uint32_t conidstschng : + 1; +uint32_t disconnect : + 1; +uint32_t sessreqintr : + 1; +uint32_t wkupintr : + 1; + } + b; +} USB_OTG_GINTSTS_TypeDef ; +typedef union _USB_OTG_DRXSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t epnum : + 4; +uint32_t bcnt : + 11; +uint32_t dpid : + 2; +uint32_t pktsts : + 4; +uint32_t fn : + 4; +uint32_t Reserved : + 7; + } + b; +} USB_OTG_DRXSTS_TypeDef ; +typedef union _USB_OTG_GRXSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t chnum : + 4; +uint32_t bcnt : + 11; +uint32_t dpid : + 2; +uint32_t pktsts : + 4; +uint32_t Reserved : + 11; + } + b; +} USB_OTG_GRXFSTS_TypeDef ; +typedef union _USB_OTG_FSIZ_TypeDef +{ + uint32_t d32; + struct + { +uint32_t startaddr : + 16; +uint32_t depth : + 16; + } + b; +} USB_OTG_FSIZ_TypeDef ; +typedef union _USB_OTG_HNPTXSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t nptxfspcavail : + 16; +uint32_t nptxqspcavail : + 8; +uint32_t nptxqtop_terminate : + 1; +uint32_t nptxqtop_timer : + 2; +uint32_t nptxqtop : + 2; +uint32_t chnum : + 2; +uint32_t Reserved : + 1; + } + b; +} USB_OTG_HNPTXSTS_TypeDef ; +typedef union _USB_OTG_DTXFSTSn_TypeDef +{ + uint32_t d32; + struct + { +uint32_t txfspcavail : + 16; +uint32_t Reserved : + 16; + } + b; +} USB_OTG_DTXFSTSn_TypeDef ; +typedef union _USB_OTG_GI2CCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t rwdata : + 8; +uint32_t regaddr : + 8; +uint32_t addr : + 7; +uint32_t i2cen : + 1; +uint32_t ack : + 1; +uint32_t i2csuspctl : + 1; +uint32_t i2cdevaddr : + 2; +uint32_t dat_se0: + 1; +uint32_t Reserved : + 1; +uint32_t rw : + 1; +uint32_t bsydne : + 1; + } + b; +} USB_OTG_GI2CCTL_TypeDef ; +typedef union _USB_OTG_GCCFG_TypeDef +{ + uint32_t d32; + struct + { +uint32_t Reserved_in : + 16; +uint32_t pwdn : + 1; +uint32_t i2cifen : + 1; +uint32_t vbussensingA : + 1; +uint32_t vbussensingB : + 1; +uint32_t sofouten : + 1; +uint32_t disablevbussensing : + 1; +uint32_t Reserved_out : + 10; + } + b; +} USB_OTG_GCCFG_TypeDef ; + +typedef union _USB_OTG_DCFG_TypeDef +{ + uint32_t d32; + struct + { +uint32_t devspd : + 2; +uint32_t nzstsouthshk : + 1; +uint32_t Reserved3 : + 1; +uint32_t devaddr : + 7; +uint32_t perfrint : + 2; +uint32_t Reserved13_17 : + 5; +uint32_t epmscnt : + 4; + } + b; +} USB_OTG_DCFG_TypeDef ; +typedef union _USB_OTG_DCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t rmtwkupsig : + 1; +uint32_t sftdiscon : + 1; +uint32_t gnpinnaksts : + 1; +uint32_t goutnaksts : + 1; +uint32_t tstctl : + 3; +uint32_t sgnpinnak : + 1; +uint32_t cgnpinnak : + 1; +uint32_t sgoutnak : + 1; +uint32_t cgoutnak : + 1; +uint32_t Reserved : + 21; + } + b; +} USB_OTG_DCTL_TypeDef ; +typedef union _USB_OTG_DSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t suspsts : + 1; +uint32_t enumspd : + 2; +uint32_t errticerr : + 1; +uint32_t Reserved4_7: + 4; +uint32_t soffn : + 14; +uint32_t Reserved22_31 : + 10; + } + b; +} USB_OTG_DSTS_TypeDef ; +typedef union _USB_OTG_DIEPINTn_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfercompl : + 1; +uint32_t epdisabled : + 1; +uint32_t ahberr : + 1; +uint32_t timeout : + 1; +uint32_t intktxfemp : + 1; +uint32_t intknepmis : + 1; +uint32_t inepnakeff : + 1; +uint32_t emptyintr : + 1; +uint32_t txfifoundrn : + 1; +uint32_t Reserved08_31 : + 23; + } + b; +} USB_OTG_DIEPINTn_TypeDef ; +typedef union _USB_OTG_DIEPINTn_TypeDef USB_OTG_DIEPMSK_TypeDef ; +typedef union _USB_OTG_DOEPINTn_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfercompl : + 1; +uint32_t epdisabled : + 1; +uint32_t ahberr : + 1; +uint32_t setup : + 1; +uint32_t Reserved04_31 : + 28; + } + b; +} USB_OTG_DOEPINTn_TypeDef ; +typedef union _USB_OTG_DOEPINTn_TypeDef USB_OTG_DOEPMSK_TypeDef ; + +typedef union _USB_OTG_DAINT_TypeDef +{ + uint32_t d32; + struct + { +uint32_t in : + 16; +uint32_t out : + 16; + } + ep; +} USB_OTG_DAINT_TypeDef ; + +typedef union _USB_OTG_DTHRCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t non_iso_thr_en : + 1; +uint32_t iso_thr_en : + 1; +uint32_t tx_thr_len : + 9; +uint32_t Reserved11_15 : + 5; +uint32_t rx_thr_en : + 1; +uint32_t rx_thr_len : + 9; +uint32_t Reserved26_31 : + 6; + } + b; +} USB_OTG_DTHRCTL_TypeDef ; +typedef union _USB_OTG_DEPCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t mps : + 11; +uint32_t reserved : + 4; +uint32_t usbactep : + 1; +uint32_t dpid : + 1; +uint32_t naksts : + 1; +uint32_t eptype : + 2; +uint32_t snp : + 1; +uint32_t stall : + 1; +uint32_t txfnum : + 4; +uint32_t cnak : + 1; +uint32_t snak : + 1; +uint32_t setd0pid : + 1; +uint32_t setd1pid : + 1; +uint32_t epdis : + 1; +uint32_t epena : + 1; + } + b; +} USB_OTG_DEPCTL_TypeDef ; +typedef union _USB_OTG_DEPXFRSIZ_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfersize : + 19; +uint32_t pktcnt : + 10; +uint32_t mc : + 2; +uint32_t Reserved : + 1; + } + b; +} USB_OTG_DEPXFRSIZ_TypeDef ; +typedef union _USB_OTG_DEP0XFRSIZ_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfersize : + 7; +uint32_t Reserved7_18 : + 12; +uint32_t pktcnt : + 2; +uint32_t Reserved20_28 : + 9; +uint32_t supcnt : + 2; + uint32_t Reserved31; + } + b; +} USB_OTG_DEP0XFRSIZ_TypeDef ; +typedef union _USB_OTG_HCFG_TypeDef +{ + uint32_t d32; + struct + { +uint32_t fslspclksel : + 2; +uint32_t fslssupp : + 1; + } + b; +} USB_OTG_HCFG_TypeDef ; +typedef union _USB_OTG_HFRMINTRVL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t frint : + 16; +uint32_t Reserved : + 16; + } + b; +} USB_OTG_HFRMINTRVL_TypeDef ; + +typedef union _USB_OTG_HFNUM_TypeDef +{ + uint32_t d32; + struct + { +uint32_t frnum : + 16; +uint32_t frrem : + 16; + } + b; +} USB_OTG_HFNUM_TypeDef ; +typedef union _USB_OTG_HPTXSTS_TypeDef +{ + uint32_t d32; + struct + { +uint32_t ptxfspcavail : + 16; +uint32_t ptxqspcavail : + 8; +uint32_t ptxqtop_terminate : + 1; +uint32_t ptxqtop_timer : + 2; +uint32_t ptxqtop : + 2; +uint32_t chnum : + 2; +uint32_t ptxqtop_odd : + 1; + } + b; +} USB_OTG_HPTXSTS_TypeDef ; +typedef union _USB_OTG_HPRT0_TypeDef +{ + uint32_t d32; + struct + { +uint32_t prtconnsts : + 1; +uint32_t prtconndet : + 1; +uint32_t prtena : + 1; +uint32_t prtenchng : + 1; +uint32_t prtovrcurract : + 1; +uint32_t prtovrcurrchng : + 1; +uint32_t prtres : + 1; +uint32_t prtsusp : + 1; +uint32_t prtrst : + 1; +uint32_t Reserved9 : + 1; +uint32_t prtlnsts : + 2; +uint32_t prtpwr : + 1; +uint32_t prttstctl : + 4; +uint32_t prtspd : + 2; +uint32_t Reserved19_31 : + 13; + } + b; +} USB_OTG_HPRT0_TypeDef ; +typedef union _USB_OTG_HAINT_TypeDef +{ + uint32_t d32; + struct + { +uint32_t chint : + 16; +uint32_t Reserved : + 16; + } + b; +} USB_OTG_HAINT_TypeDef ; +typedef union _USB_OTG_HAINTMSK_TypeDef +{ + uint32_t d32; + struct + { +uint32_t chint : + 16; +uint32_t Reserved : + 16; + } + b; +} USB_OTG_HAINTMSK_TypeDef ; +typedef union _USB_OTG_HCCHAR_TypeDef +{ + uint32_t d32; + struct + { +uint32_t mps : + 11; +uint32_t epnum : + 4; +uint32_t epdir : + 1; +uint32_t Reserved : + 1; +uint32_t lspddev : + 1; +uint32_t eptype : + 2; +uint32_t multicnt : + 2; +uint32_t devaddr : + 7; +uint32_t oddfrm : + 1; +uint32_t chdis : + 1; +uint32_t chen : + 1; + } + b; +} USB_OTG_HCCHAR_TypeDef ; +typedef union _USB_OTG_HCSPLT_TypeDef +{ + uint32_t d32; + struct + { +uint32_t prtaddr : + 7; +uint32_t hubaddr : + 7; +uint32_t xactpos : + 2; +uint32_t compsplt : + 1; +uint32_t Reserved : + 14; +uint32_t spltena : + 1; + } + b; +} USB_OTG_HCSPLT_TypeDef ; +typedef union _USB_OTG_HCINTn_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfercompl : + 1; +uint32_t chhltd : + 1; +uint32_t ahberr : + 1; +uint32_t stall : + 1; +uint32_t nak : + 1; +uint32_t ack : + 1; +uint32_t nyet : + 1; +uint32_t xacterr : + 1; +uint32_t bblerr : + 1; +uint32_t frmovrun : + 1; +uint32_t datatglerr : + 1; +uint32_t Reserved : + 21; + } + b; +} USB_OTG_HCINTn_TypeDef ; +typedef union _USB_OTG_HCTSIZn_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfersize : + 19; +uint32_t pktcnt : + 10; +uint32_t pid : + 2; +uint32_t dopng : + 1; + } + b; +} USB_OTG_HCTSIZn_TypeDef ; +typedef union _USB_OTG_HCGINTMSK_TypeDef +{ + uint32_t d32; + struct + { +uint32_t xfercompl : + 1; +uint32_t chhltd : + 1; +uint32_t ahberr : + 1; +uint32_t stall : + 1; +uint32_t nak : + 1; +uint32_t ack : + 1; +uint32_t nyet : + 1; +uint32_t xacterr : + 1; +uint32_t bblerr : + 1; +uint32_t frmovrun : + 1; +uint32_t datatglerr : + 1; +uint32_t Reserved : + 21; + } + b; +} USB_OTG_HCGINTMSK_TypeDef ; +typedef union _USB_OTG_PCGCCTL_TypeDef +{ + uint32_t d32; + struct + { +uint32_t stoppclk : + 1; +uint32_t gatehclk : + 1; +uint32_t Reserved : + 30; + } + b; +} USB_OTG_PCGCCTL_TypeDef ; + +/** + * @} + */ + + +/** @defgroup USB_REGS_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_REGS_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USB_REGS_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + + +#endif //__USB_OTG_REGS_H__ + + +/** + * @} + */ + +/** + * @} + */ +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ + |
