updated ui added new features

This commit is contained in:
zach
2025-12-27 15:32:32 -07:00
parent 02ca7801ea
commit a2cfae3a22
589 changed files with 181780 additions and 569 deletions
+311
View File
@@ -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)
+101
View File
@@ -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
+348
View File
@@ -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")
+15
View File
@@ -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 "")
+64
View File
@@ -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})
+173
View File
@@ -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}
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

+184
View File
@@ -0,0 +1,184 @@
# SM1000 Manual
![SM1000 front view](sm1000_enc_sm.jpg)
# 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.
![](3dot5mm_cable_config.png)
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:
![](sm1000_cn12_rev2.png)
![](sm1000_cn4_cn12.jpg)
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 doesnt 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 youll 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 its Digital Voice. A louder microphone signal wont 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!
+35
View File
@@ -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
+13
View File
@@ -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
+92
View File
@@ -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 <me@vk4msl.id.au>
* 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
+65
View File
@@ -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 <me@vk4msl.id.au>
* 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
+63
View File
@@ -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 <me@vk4msl.id.au>
* 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
+86
View File
@@ -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
+38
View File
@@ -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 <me@vk4msl.id.au>
* 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
+46
View File
@@ -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
+46
View File
@@ -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
+35
View File
@@ -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
+24
View File
@@ -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
+70
View File
@@ -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 <me@vk4msl.id.au>
* 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
+94
View File
@@ -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>&copy; 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****/
+84
View File
@@ -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 <me@vk4msl.id.au>
* 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
+115
View File
@@ -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 <me@vk4msl.id.au>
* 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
+85
View File
@@ -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);
}
}
+57
View File
@@ -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);
}
}
+57
View File
@@ -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 */
}
}
+67
View File
@@ -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;
}
}
}
+98
View File
@@ -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 <me@vk4msl.id.au>
* 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);
}
+175
View File
@@ -0,0 +1,175 @@
/*!
* Morse code library.
*
* This implements a state machine for playing back morse code messages.
*
* Author Stuart Longland <me@vk4msl.id.au>
* 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));
}
+67
View File
@@ -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 <me@vk4msl.id.au>
* 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));
}
+229
View File
@@ -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;
}
+41
View File
@@ -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());
}
}
File diff suppressed because it is too large Load Diff
+62
View File
@@ -0,0 +1,62 @@
/*!
* Sound effect library.
*
* This provides some sound effects for the SM1000 UI.
*
* Author Stuart Longland <me@vk4msl.id.au>
* 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},
};
+526
View File
@@ -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>&copy; 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****/
+286
View File
@@ -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);
}
+427
View File
@@ -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
generation 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);
}
+92
View File
@@ -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;
}
+71
View File
@@ -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;
}
+90
View File
@@ -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);
}
+724
View File
@@ -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 <me@vk4msl.id.au>
* 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;
}
+585
View File
@@ -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>&copy; 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****/
+151
View File
@@ -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 <me@vk4msl.id.au>
* 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;
}
+90
View File
@@ -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 <me@vk4msl.id.au>
* 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;
}
+30
View File
@@ -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);
}
}
+96
View File
@@ -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++;
}
+192
View File
@@ -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);
}
+145
View File
@@ -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
+14
View File
@@ -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
+428
View File
@@ -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 <whitequark@whitequark.org>
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
+151
View File
@@ -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
}
+116
View File
@@ -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
}
+259
View File
@@ -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:
@@ -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
+51
View File
@@ -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)
Binary file not shown.
+25
View File
@@ -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
+15
View File
@@ -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))
+54
View File
@@ -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)
+27
View File
@@ -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:
+26
View File
@@ -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:
+32
View File
@@ -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:
+25
View File
@@ -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:
+91
View File
@@ -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
+53
View File
@@ -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:
@@ -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
}
+19
View File
@@ -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}
@@ -0,0 +1,2 @@
semihosting test - stderr
Error 2 opening fin
@@ -0,0 +1 @@
semihosting test - stdout
+45
View File
@@ -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)
+214
View File
@@ -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
+151
View File
@@ -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
+115
View File
@@ -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
+86
View File
@@ -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
+43
View File
@@ -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
+54
View File
@@ -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
+59
View File
@@ -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
+54
View File
@@ -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
+71
View File
@@ -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
+50
View File
@@ -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
+68
View File
@@ -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
+39
View File
@@ -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
+503
View File
@@ -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)
+100
View File
@@ -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
+65
View File
@@ -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
+42
View File
@@ -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
+161
View File
@@ -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)
+745
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
/*
* Dummy function to avoid compiler error
*/
void _init() {
}
void _fini() {
}
+19
View File
@@ -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: */
+7
View File
@@ -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: */
@@ -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>&copy; 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****/
+235
View File
@@ -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: */
@@ -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: */
+274
View File
@@ -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: */

Some files were not shown because too many files have changed in this diff Show More