├── .gitignore ├── .gitmodules ├── README.md ├── board_stm32f4_dis_bb ├── board.c ├── board.h └── board.mk ├── python_playback ├── debug_generator.py ├── debug_logger.py ├── main.py ├── playback.py ├── receiver.py └── stm32.py ├── stm32_streaming ├── Makefile ├── audio │ ├── audio_control_server.c │ ├── audio_control_server.h │ ├── audio_tx.c │ ├── audio_tx.h │ ├── autogen_fir_coeffs.c │ ├── autogen_fir_coeffs.h │ ├── mp45dt02_processing.c │ └── mp45dt02_processing.h ├── chconf.h ├── config.h ├── halconf.h ├── lwipopts.h ├── main.c ├── mcuconf.h ├── random │ ├── random.c │ └── random.h ├── rtp │ ├── rtp.c │ └── rtp.h └── utils │ ├── debug.c │ └── debug.h ├── test ├── cmsis_fir_filters │ ├── README.md │ ├── src │ │ ├── Makefile │ │ ├── chconf.h │ │ ├── halconf.h │ │ ├── main.c │ │ └── mcuconf.h │ └── utils │ │ ├── compare.py │ │ └── design.py ├── lwip_basic_udp │ ├── README.md │ ├── src │ │ ├── Makefile │ │ ├── chconf.h │ │ ├── halconf.h │ │ ├── lan8720.c │ │ ├── lwipopts.h │ │ ├── main.c │ │ ├── mcuconf.h │ │ └── project.h │ └── utils │ │ ├── gdb_openocd.cfg │ │ ├── udp_echo_test.py │ │ └── udp_max_throughput_tester.py ├── mp45dt02_basic_cmsis_filtering │ ├── README.md │ ├── src │ │ ├── Makefile │ │ ├── autogen_fir_coeffs.c │ │ ├── autogen_fir_coeffs.h │ │ ├── chconf.h │ │ ├── debug.c │ │ ├── debug.h │ │ ├── halconf.h │ │ ├── main.c │ │ ├── mcuconf.h │ │ ├── mp45dt02_pdm.c │ │ └── mp45dt02_pdm.h │ └── utils │ │ ├── fir_design.py │ │ ├── gdb_openocd.cfg │ │ ├── generate_tone_wav_file.py │ │ └── signal_inspection_of_gdb_log.py └── true_random_number_generator │ ├── README.md │ ├── src │ ├── Makefile │ ├── chconf.h │ ├── halconf.h │ ├── ip_random_tx.c │ ├── lwipopts.h │ ├── main.c │ ├── mcuconf.h │ ├── project.h │ ├── random.c │ └── random.h │ └── utils │ ├── file_to_png.py │ ├── gdb_openocd.cfg │ └── random_receiver.py └── utils ├── cscope.sh ├── fir_design.py └── gdb_openocd.cfg /.gitignore: -------------------------------------------------------------------------------- 1 | **/build/ 2 | **/.dep/ 3 | **/output/ 4 | **/__pycache__/ 5 | *.log 6 | *.wav 7 | *.png 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ChibiOS"] 2 | path = lib/ChibiOS 3 | url = git@github.com:ChibiOS/ChibiOS.git 4 | [submodule "lib/CMSIS"] 5 | path = lib/CMSIS 6 | url = git@github.com:ARM-software/CMSIS.git 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STM32F4 Streaming Microphone 2 | 3 | This project runs on the STM32F4Discovery (STM32F407 variant) in combination 4 | with the STM32F4DIS-EXT expansion board. 5 | 6 | The on-board MP45DT02 MEMS microphone is sampled and filtered to produce a 16 7 | kHz PCM audio signal. This is streamed over UDP via the LAN8720 Ethernet Phy on 8 | the expansion board. 9 | 10 | A simple Python script is provided to receive and play the audio stream. 11 | 12 | This project was a learning exercise and should be considered as little more 13 | than a proof of concept. If it is of interest to you, may also 14 | want to check out some relevant [blog posts]( 15 | https://www.theunterminatedstring.com/tag/project_stm32_streaming_mic/) 16 | written along the way. 17 | 18 | # Building and Running 19 | 20 | ## 1. Update submodules 21 | 22 | git submodule update --init --recursive 23 | 24 | ## 2. Extract LWIP 25 | 26 | The LWIP source code should be extracted from the ChibiOS repository. 27 | 28 | Assuming the current working directory the top level of the repo, issue the 29 | following commands to extract LWIP. This assumes 7z is available on your system. 30 | 31 | cd lib/ChibiOS/ext 32 | 7z x lwip-1.4.1_patched.7z 33 | cd - 34 | 35 | ## 3. Configure as Required 36 | 37 | Modify `stm32_streaming/config.h` with the desired static IP configuration. 38 | 39 | ## 4. Build 40 | 41 | cd stm32_streaming 42 | make 43 | cd - 44 | 45 | ## 5. Program 46 | 47 | (Assuming you have an [OpenOCD](openocd.org) binary). 48 | 49 | ./openocd -f board/stm32f4discovery.cfg -f interface/stlink-v2-1.cfg -c "stm32f4x.cpu configure -rtos ChibiOS" 50 | 51 | cd stm32_streaming 52 | arm-none-eabi-gdb -x ../utils/gdb_openocd.cfg 53 | 54 | ## 6. Streaming 55 | 56 | In a separate terminal run the Python script to trigger and receive the audio 57 | stream. The available command line options can be printed by passing in 58 | `--help`. 59 | 60 | cd python_playback 61 | ./main.py --help 62 | 63 | An example of invoking this script is: 64 | 65 | ./main.py --local-ip 192.168.1.154 --local-port 41234 --device-ip 192.168.1.60 --device-port 20000 --run-time 2 66 | 67 | ## 7. Serial Output / Logging 68 | 69 | There is some minor debug output printed from the STM32 using ChibiOS SD1 driver 70 | over GPIOB pins 6 and 7. 71 | 72 | minicom --device=/dev/ttyUSB0 --baudrate=38400 73 | 74 | # Debian Misc Commands 75 | 76 | - `amixer set Master 25%` Change volume 77 | - `eog ` Open png image 78 | - `aplay ` Play audio file 79 | 80 | # STM32 Architecture Overview 81 | 82 | ## stm32_streaming/audio/audio_control_server.c 83 | 84 | This module is responsible for setting up an LWIP TCP server, bound to TCP port 85 | 20000. This server accepts two ASCII commands: 86 | 87 | - `start ` where ip, port is the target address for the UDP audio 88 | stream. These are both provided in hexidecimal format, with leading zeros 89 | present as necessary. 90 | 91 | - `stop` stop a running audio stream 92 | 93 | ## stm32_streaming/audio/mp45dt02_processing.c 94 | 95 | This file handles (over) sampling the MP45DT02 MEMS microphone as well as 96 | running a CMSIS FIR filter over the data. The FIR coefficients can be found in 97 | `stm32_streaming/audio/autogen_fir_coeffs.c` which are generated using 98 | `utils/fir_design.py` 99 | 100 | ## stm32_streaming/audio/audio_tx.c 101 | 102 | This module tracks when 20 ms of audio has been collected from the MP45DT02. 103 | Once a full payload has been stored, it requests `rtp/rtp.c` add a RTP header to 104 | the payload and then transmits the data over UDP to the address previously 105 | specified by the user. 106 | 107 | ## Dependencies 108 | 109 | The STM32 binary requires the following libraries: 110 | 111 | - [ChibiOS](http://www.chibios.org/dokuwiki/doku.php) for RTOS + HAL 112 | - [LWIP](https://savannah.nongnu.org/projects/lwip/) for IP/UDP/TCP 113 | - [CMSIS](https://developer.arm.com/embedded/cmsis) for FIR DSP 114 | 115 | These should be met by following the steps listed above to build the project. 116 | 117 | # Python Playback Software 118 | 119 | In `python_playback` there are a handful of Python scripts which will request, 120 | recieve and play the audio stream. There are also some additional debug modules. 121 | See the run steps above for an example of running `main.py` with arguments. 122 | 123 | ## python_playback/stm32.py 124 | 125 | Connects to the STM32 over TCP and requests that the STM32 start/stop 126 | streaming audio. 127 | 128 | ## python_playback/receiver.py 129 | 130 | Spawns a thread to receive the UDP packets from the STM32 and extract the audio 131 | payload from them. These frames are added to a queue for consumption by a 132 | different thread. 133 | 134 | ## python_playback/playback.py 135 | 136 | Responsible for initially buffering audio packets popped from the queue and then 137 | playing the stream via PyAudio. 138 | The amount of buffering, chosen through trial and error, was what would 139 | reliability work on my system. This approach was also used when picking the 140 | default frame size passed to PyAudio of 1600 samples (10% sampling rate). 141 | 142 | ## Dependencies 143 | 144 | Core functionality requires `pyaudio`, with some of the debug utilities 145 | requiring `matplotlib` and `numpy`. The following commands should hopefully 146 | obtain everything you need on a Debian system. 147 | 148 | apt-get install python3-pyaudio 149 | apt-get install python3-matplotlib python3-numpy 150 | 151 | # Issues / Limitations 152 | 153 | ## RTP 154 | 155 | This project borrows the RTP header to stream the audio data. There is no actual 156 | RTP implementation. 157 | This wasn't always the case as I had hoped to let 158 | [VLC](https://www.videolan.org/vlc/index.en-GB.html) take care of playback for 159 | me. 160 | I made some headway implementing what I considered the minimum required 161 | functionality from the follow specifications: 162 | 163 | * Real-Time Streaming Protocol (RTSP) ([RFC2326](https://tools.ietf.org/html/rfc2326)) 164 | * Real-Time Transport Protocol (RTP) [RFC3550](https://tools.ietf.org/html/rfc3550) 165 | * Real-Time Transport Protocol [RTP](https://tools.ietf.org/html/rfc3550#page-13) 166 | * Real-Time Control Protocol [RTCP](https://tools.ietf.org/html/rfc3550#page-19) 167 | * Session Description Protocol (SDP) [RFC4566](https://tools.ietf.org/html/rfc4566) 168 | 169 | However I eventually gave up on this approach due to a mixture of getting fed 170 | up, and VLC appearing to expect non-standard RTSP headers. 171 | 172 | ## Python PyAudio Playback 173 | 174 | I hoped for a low latency audio stream but ran into some issues with 175 | PyAudio/PortAudio when trying to play 20 ms audio frames. The callback from 176 | PortAudio was trying to consume data a lot faster than it was being provided. 177 | Buffering a few packets alone didn't appear to alleviate PortAudio's hunger, and 178 | neither did bumping the frame/chunk size. So both approaches were taken. 179 | 180 | Note that this may be something to do with my specific hardware or the 181 | VM I was attempting to play it back through. Debugging audio playback wasn't 182 | something I particularly wanted to do - which is why I originally planned on 183 | using VLC to avoid it altogether. 184 | 185 | Finally, there is no Python code in place to handle lost / out of order 186 | frames. The RTP sequence number in the packets is completely ignored. 187 | 188 | -------------------------------------------------------------------------------- /board_stm32f4_dis_bb/board.c: -------------------------------------------------------------------------------- 1 | /* 2 | ChibiOS/RT - Copyright (C) 2006-2014 Giovanni Di Sirio 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Modified by Alan Barr, 2016. 17 | */ 18 | 19 | #include "hal.h" 20 | 21 | #if HAL_USE_PAL || defined(__DOXYGEN__) 22 | /** 23 | * @brief PAL setup. 24 | * @details Digital I/O ports static configuration as defined in @p board.h. 25 | * This variable is used by the HAL when initializing the PAL driver. 26 | */ 27 | const PALConfig pal_default_config = 28 | { 29 | {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, 30 | VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, 31 | {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, 32 | VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH}, 33 | {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, 34 | VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH}, 35 | {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, 36 | VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH}, 37 | {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, 38 | VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH}, 39 | {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, 40 | VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH}, 41 | {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, 42 | VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH}, 43 | {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, 44 | VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH}, 45 | {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, 46 | VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH} 47 | }; 48 | #endif 49 | 50 | /** 51 | * @brief Early initialization code. 52 | * @details This initialization must be performed just after stack setup 53 | * and before any other initialization. 54 | */ 55 | void __early_init(void) 56 | { 57 | stm32_clock_init(); 58 | } 59 | 60 | #if HAL_USE_SDC || defined(__DOXYGEN__) 61 | /** 62 | * @brief SDC card detection. 63 | */ 64 | bool sdc_lld_is_card_inserted(SDCDriver *sdcp) 65 | { 66 | (void)sdcp; 67 | /* TODO: Fill the implementation.*/ 68 | return TRUE; 69 | } 70 | 71 | /** 72 | * @brief SDC card write protection detection. 73 | */ 74 | bool sdc_lld_is_write_protected(SDCDriver *sdcp) 75 | { 76 | (void)sdcp; 77 | /* TODO: Fill the implementation.*/ 78 | return FALSE; 79 | } 80 | #endif /* HAL_USE_SDC */ 81 | 82 | #if HAL_USE_MMC_SPI || defined(__DOXYGEN__) 83 | /** 84 | * @brief MMC_SPI card detection. 85 | */ 86 | bool mmc_lld_is_card_inserted(MMCDriver *mmcp) 87 | { 88 | (void)mmcp; 89 | /* TODO: Fill the implementation.*/ 90 | return TRUE; 91 | } 92 | 93 | /** 94 | * @brief MMC_SPI card write protection detection. 95 | */ 96 | bool mmc_lld_is_write_protected(MMCDriver *mmcp) 97 | { 98 | (void)mmcp; 99 | /* TODO: Fill the implementation.*/ 100 | return FALSE; 101 | } 102 | #endif 103 | 104 | /* I don't think any of ChibiOS default timing mechanisms will be initialised at 105 | * the point the board functions will be called. 106 | * Just a dumb loop for now. Will do for minimum wait times. */ 107 | static void boardWait(volatile uint32_t count) 108 | { 109 | while (count--); 110 | } 111 | 112 | void boardPhyReset(void) 113 | { 114 | palClearPad(GPIOE, GPIOE_LAN8720_NRST); 115 | boardWait(16800000); 116 | palSetPad(GPIOE, GPIOE_LAN8720_NRST); 117 | boardWait(16800000); 118 | } 119 | 120 | 121 | /** 122 | * @brief Board-specific initialization code. 123 | * @todo Add your board-specific code, if any. 124 | */ 125 | void boardInit(void) 126 | { 127 | 128 | } 129 | -------------------------------------------------------------------------------- /board_stm32f4_dis_bb/board.mk: -------------------------------------------------------------------------------- 1 | # List of all the board related files. 2 | BOARDSRC = ${BOARD}/board.c 3 | 4 | # Required include directories 5 | BOARDINC = ${BOARD}/ 6 | -------------------------------------------------------------------------------- /python_playback/debug_generator.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import socket 29 | import operator 30 | import struct 31 | import threading 32 | import time 33 | import numpy 34 | 35 | 36 | ################################################################################ 37 | # Configuration 38 | ################################################################################ 39 | # The list of frequencies to be superimposed in the output wave form 40 | freqs = [500, 2000, 4000, 7000, 10000, 11000] 41 | 42 | 43 | class AudioDebugGenerator(object): 44 | 45 | def __init__(self, 46 | sink_ip, 47 | sink_port, 48 | sampling_freq, 49 | samples_per_message): 50 | 51 | self.bytes_per_msg = samples_per_message * 2 52 | 53 | self.between_packet_sleep = 1.0 / (sampling_freq/samples_per_message) 54 | 55 | self.sink_ip = sink_ip 56 | self.sink_port = sink_port 57 | self.tx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 58 | 59 | self.should_stop = threading.Event() 60 | 61 | self._init_signal(sampling_freq=sampling_freq) 62 | 63 | def _init_signal(self, sampling_freq): 64 | audio_signal = [0] * sampling_freq 65 | 66 | t = numpy.arange(sampling_freq) / float(sampling_freq) 67 | 68 | for freq in freqs: 69 | tone = numpy.cos(t*2*numpy.pi*freq) 70 | audio_signal = list(map(operator.add, audio_signal, tone)) 71 | 72 | scaling = 32760 / numpy.max(audio_signal) 73 | 74 | self.signal = b"" 75 | for sample in audio_signal: 76 | sample = sample * scaling 77 | self.signal += struct.pack("h", int(sample)) 78 | 79 | def _stream_data(self): 80 | while self.should_stop.is_set() is False: 81 | message = "FakeRTPHeadr".encode("ASCII") + \ 82 | self.signal[0:self.bytes_per_msg] 83 | self.tx_sock.sendto(message, (self.sink_ip, self.sink_port)) 84 | time.sleep(self.between_packet_sleep) 85 | 86 | def start(self): 87 | self.should_stop.clear() 88 | self.tx_thread = threading.Thread(target=self._stream_data) 89 | self.tx_thread.start() 90 | print("started tx thread") 91 | 92 | def stop(self): 93 | self.should_stop.set() 94 | self.tx_thread.join() 95 | -------------------------------------------------------------------------------- /python_playback/debug_logger.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import matplotlib.pyplot as plot 29 | import wave 30 | import struct 31 | 32 | class AudioDebugLogger(object): 33 | 34 | def __init__(self, queue, sampling_freq, output_base_name): 35 | 36 | self._queue = queue 37 | self._sampling_freq = sampling_freq 38 | self._filebase = output_base_name 39 | 40 | def run(self): 41 | self._captured_bytes = b"" 42 | self._captured_ints = [] 43 | 44 | while self._queue.qsize(): 45 | parsed = self._queue.get() 46 | self._captured_bytes += parsed 47 | 48 | def save_plot(self): 49 | 50 | # to length of int16s 51 | samples = int(len(self._captured_bytes) / 2) 52 | 53 | conversion_str = "h" * samples 54 | 55 | ints = struct.unpack(conversion_str, self._captured_bytes) 56 | 57 | plot.plot(ints) 58 | plot.grid() 59 | plot.savefig(self._filebase + ".png") 60 | plot.close() 61 | 62 | def save_wave_file(self): 63 | 64 | wav = wave.open(self._filebase + ".wav", "w") 65 | 66 | wav.setparams((1, # nchannels 67 | 2, # sampwidth 68 | self._sampling_freq, # framerate 69 | 0, # nframes 70 | "NONE", # comptype 71 | "not compressed" # compname 72 | )) 73 | 74 | wav.writeframes(self._captured_bytes) 75 | wav.close() 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /python_playback/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import time 29 | import queue 30 | import argparse 31 | 32 | from receiver import AudioReceiver 33 | from debug_logger import AudioDebugLogger 34 | from debug_generator import AudioDebugGenerator 35 | from playback import AudioPlayback 36 | from stm32 import Stm32AudioSource 37 | 38 | 39 | def stream(sink_ip, 40 | sink_port, 41 | device_ip=None, 42 | device_port=None, 43 | run_time=5, 44 | save=False): 45 | 46 | sampling_freq = 16000 47 | 48 | audio_queue = queue.Queue() 49 | queues = [audio_queue] 50 | 51 | if save: 52 | debug_queue = queue.Queue() 53 | queues += [debug_queue] 54 | 55 | receiver = AudioReceiver(sink_ip=sink_ip, 56 | sink_port=sink_port, 57 | queues=queues) 58 | receiver.run() 59 | 60 | if device_ip: 61 | audio_source = Stm32AudioSource(stm32_ip=device_ip, 62 | stm32_port=device_port, 63 | sink_ip=sink_ip, 64 | sink_port=sink_port) 65 | else: 66 | print("device ip not specified - generating local audio") 67 | audio_source = AudioDebugGenerator(sink_ip=sink_ip, 68 | sink_port=sink_port, 69 | sampling_freq=sampling_freq, 70 | samples_per_message=320) 71 | 72 | audio_source.start() 73 | 74 | playback = AudioPlayback(queue=audio_queue, 75 | sampling_freq=sampling_freq) 76 | playback.start() 77 | 78 | while run_time: 79 | time.sleep(1) 80 | run_time -= 1 81 | 82 | playback.stop() 83 | receiver.close() 84 | audio_source.stop() 85 | 86 | if save: 87 | audio_logger = AudioDebugLogger(queue=debug_queue, 88 | output_base_name="samples", 89 | sampling_freq=sampling_freq) 90 | audio_logger.run() 91 | audio_logger.save_plot() 92 | audio_logger.save_wave_file() 93 | 94 | 95 | if __name__ == "__main__": 96 | 97 | parser = argparse.ArgumentParser(description=""" 98 | Starts, receives and plays an audio stream from a STM32 running 99 | the companion software. """) 100 | 101 | parser.add_argument("--device-ip", 102 | nargs="?", 103 | type=str, 104 | help="STM32 IP Address." 105 | "If this is not provided a test/debug signal is " 106 | "generated.") 107 | 108 | parser.add_argument("--device-port", 109 | nargs="?", 110 | type=int, 111 | help="STM32 management channel port number.") 112 | 113 | parser.add_argument("--local-ip", 114 | nargs="?", 115 | type=str, 116 | help="Local IP address to use.") 117 | 118 | parser.add_argument("--local-port", 119 | nargs="?", 120 | type=int, 121 | default=54321, 122 | help="Local UDP port number to receive audio data on.") 123 | 124 | parser.add_argument("--save-samples", 125 | action="store_true", 126 | help="Save recorded audio and graph. " 127 | "Be mindful of the running time when using this " 128 | "option.") 129 | 130 | parser.add_argument("--run-time", 131 | nargs="?", 132 | type=int, 133 | default=5, 134 | help="Run for specified number of seconds. " 135 | "Actual run time will be slightly longer than this.") 136 | 137 | cli_args = parser.parse_args() 138 | 139 | print(cli_args) 140 | 141 | stream(sink_ip=cli_args.local_ip, 142 | sink_port=cli_args.local_port, 143 | device_ip=cli_args.device_ip, 144 | device_port=cli_args.device_port, 145 | save=cli_args.save_samples, 146 | run_time=cli_args.run_time) 147 | -------------------------------------------------------------------------------- /python_playback/playback.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import queue 29 | import pyaudio 30 | import struct 31 | import time 32 | import math 33 | 34 | class AudioPlayback(object): 35 | 36 | def __init__(self, queue, sampling_freq, frame_count=None, is_blocking=False): 37 | 38 | self.frame_count = frame_count if frame_count is not None else sampling_freq/10 39 | self.frame_count = int(self.frame_count) 40 | 41 | self.is_blocking = is_blocking 42 | self.sampling_freq = sampling_freq 43 | 44 | self._queue = queue 45 | 46 | self.last_time = time.time() 47 | 48 | def start(self): 49 | 50 | if self.is_blocking: 51 | cb = None 52 | else: 53 | cb = self._streaming_callback 54 | 55 | # Empty audio frame to insert when no data 56 | self._empty_frame = self.frame_count * struct.pack("h", 0) 57 | 58 | self.pyaudio = pyaudio.PyAudio() 59 | 60 | self._fresh_buffering() 61 | 62 | self.stream = self.pyaudio.open(format=pyaudio.paInt16, 63 | channels=1, 64 | rate=self.sampling_freq, 65 | output=True, 66 | stream_callback=cb, 67 | frames_per_buffer=self.frame_count) 68 | 69 | def _fresh_buffering(self): 70 | 71 | message = self._queue.get() 72 | self._leftover_bytes = message 73 | 74 | min_queue_len = float(len(self._empty_frame)) / len(self._leftover_bytes) 75 | min_queue_len = math.ceil(min_queue_len) 76 | min_queue_len *= 8 77 | 78 | while (self._queue.qsize() < min_queue_len): 79 | time.sleep(0.010) 80 | 81 | def _streaming_callback(self, in_data, frame_count, time_info, status): 82 | 83 | self.last_time = time.time() 84 | 85 | new_frame = b"" 86 | missing_bytes = frame_count * 2 87 | 88 | if len(self._leftover_bytes): 89 | new_frame += self._leftover_bytes 90 | missing_bytes -= len(self._leftover_bytes) 91 | self._leftover_bytes = b"" 92 | 93 | while missing_bytes > 0: 94 | 95 | if self._queue.empty(): 96 | new_frame += self._empty_frame[0:missing_bytes] 97 | missing_bytes = 0 98 | print("using empty") 99 | else: 100 | message = self._queue.get() 101 | new_frame += message 102 | missing_bytes -= len(message) 103 | 104 | # Save any excess for next time around 105 | if (missing_bytes < 0): 106 | self._leftover_bytes = new_frame[missing_bytes::1] 107 | 108 | return (new_frame, pyaudio.paContinue) 109 | 110 | def write(self, timeout): 111 | end_time = time.time() + timeout 112 | 113 | while time.time() < end_time: 114 | self.last_time = time.time() 115 | 116 | message = self._queue.get() 117 | 118 | before_write = time.time() 119 | self.stream.write(message) 120 | 121 | def stop(self): 122 | self.stream.stop_stream() 123 | self.stream.close() 124 | self.pyaudio.terminate() 125 | 126 | 127 | -------------------------------------------------------------------------------- /python_playback/receiver.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import threading 29 | import socket 30 | import struct 31 | 32 | RTP_HEADER_LEN = 12 33 | UINT16_LEN = 2 34 | 35 | class AudioReceiver(object): 36 | 37 | def __init__(self, sink_ip, sink_port, queues): 38 | 39 | self._rx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 40 | self._rx_sock.bind((sink_ip, sink_port)) 41 | self._queues = queues 42 | 43 | @staticmethod 44 | def _get_rtp_header(rx_data): 45 | rtp_header_str = "!ccHII" 46 | (b1, b2, sequence, timestamp, ssrc) = struct.unpack(rtp_header_str, 47 | rx_data[:RTP_HEADER_LEN]) 48 | return (b1, b2, sequence, timestamp, ssrc) 49 | 50 | @staticmethod 51 | def _get_rtp_payload(rx_data): 52 | 53 | len_uint16s = int(len(rx_data[RTP_HEADER_LEN:]) / UINT16_LEN) 54 | 55 | conversion_str = "!" + "h" * len_uint16s 56 | 57 | payload_ints = struct.unpack(conversion_str, rx_data[RTP_HEADER_LEN:]) 58 | 59 | payload_bytes = b"" 60 | for sample in payload_ints: 61 | payload_bytes += struct.pack("h", sample) 62 | 63 | return (payload_ints, payload_bytes) 64 | 65 | def _socket_receiver(self): 66 | 67 | while self._should_stop.is_set() == False: 68 | parsed = {} 69 | (data_bytes, (src_ip, src_port)) = self._rx_sock.recvfrom(65535) 70 | (parsed["ints"], parsed["bytes"]) = self._get_rtp_payload(data_bytes) 71 | 72 | for q in self._queues: 73 | q.put(parsed["bytes"]) 74 | 75 | def run(self): 76 | self._should_stop = threading.Event() 77 | self._rx_thread = threading.Thread(target=self._socket_receiver) 78 | self._rx_thread.start() 79 | 80 | def close(self): 81 | self._should_stop.set() 82 | self._rx_thread.join() 83 | self._rx_sock.close() 84 | 85 | 86 | -------------------------------------------------------------------------------- /python_playback/stm32.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import socket 29 | import ipaddress 30 | 31 | class Stm32AudioSource(object): 32 | 33 | def __init__(self, stm32_ip, stm32_port, sink_ip, sink_port): 34 | 35 | self.ip = stm32_ip 36 | self.port = stm32_port 37 | self.sink_ip = sink_ip 38 | self.sink_port = sink_port 39 | 40 | def start(self): 41 | 42 | args = list(ipaddress.ip_address(self.sink_ip).packed) + [self.sink_port] 43 | 44 | cmd = "start {:02x}{:02x}{:02x}{:02x} {:04x}".format(*args) 45 | 46 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 47 | sock.connect((self.ip, self.port)) 48 | sock.send(cmd.encode("ASCII")) 49 | sock.close() 50 | 51 | def stop(self): 52 | 53 | cmd = "stop" 54 | 55 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 56 | sock.connect((self.ip, self.port)) 57 | sock.send(cmd.encode("ASCII")) 58 | sock.close() 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /stm32_streaming/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build global options 3 | # NOTE: Can be overridden externally. 4 | # 5 | 6 | # Compiler options here. 7 | ifeq ($(USE_OPT),) 8 | USE_OPT = -O2 -ggdb3 -fomit-frame-pointer -falign-functions=16 9 | endif 10 | 11 | # C specific options here (added to USE_OPT). 12 | ifeq ($(USE_COPT),) 13 | USE_COPT = 14 | endif 15 | 16 | # C++ specific options here (added to USE_OPT). 17 | ifeq ($(USE_CPPOPT),) 18 | USE_CPPOPT = -fno-rtti 19 | endif 20 | 21 | # Enable this if you want the linker to remove unused code and data 22 | ifeq ($(USE_LINK_GC),) 23 | USE_LINK_GC = yes 24 | endif 25 | 26 | # Linker extra options here. 27 | ifeq ($(USE_LDOPT),) 28 | USE_LDOPT = 29 | endif 30 | 31 | # Enable this if you want link time optimizations (LTO) 32 | ifeq ($(USE_LTO),) 33 | USE_LTO = no 34 | endif 35 | 36 | # If enabled, this option allows to compile the application in THUMB mode. 37 | ifeq ($(USE_THUMB),) 38 | USE_THUMB = yes 39 | endif 40 | 41 | # Enable this if you want to see the full log while compiling. 42 | ifeq ($(USE_VERBOSE_COMPILE),) 43 | USE_VERBOSE_COMPILE = no 44 | endif 45 | 46 | # If enabled, this option makes the build process faster by not compiling 47 | # modules not used in the current configuration. 48 | ifeq ($(USE_SMART_BUILD),) 49 | USE_SMART_BUILD = yes 50 | endif 51 | 52 | # 53 | # Build global options 54 | ############################################################################## 55 | 56 | ############################################################################## 57 | # Architecture or project specific options 58 | # 59 | 60 | # Stack size to be allocated to the Cortex-M process stack. This stack is 61 | # the stack used by the main() thread. 62 | ifeq ($(USE_PROCESS_STACKSIZE),) 63 | USE_PROCESS_STACKSIZE = 0x400 64 | endif 65 | 66 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This 67 | # stack is used for processing interrupts and exceptions. 68 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) 69 | USE_EXCEPTIONS_STACKSIZE = 0x400 70 | endif 71 | 72 | # Enables the use of FPU on Cortex-M4 (no, softfp, hard). 73 | ifeq ($(USE_FPU),) 74 | USE_FPU = hard 75 | endif 76 | 77 | # 78 | # Architecture or project specific options 79 | ############################################################################## 80 | 81 | ############################################################################## 82 | # Project, sources and paths 83 | # 84 | 85 | # Define project name here 86 | PROJECT = streaming_mic 87 | 88 | # Imported source files and paths 89 | CHIBIOS = ../lib/ChibiOS 90 | CMSIS= ../lib/CMSIS/CMSIS 91 | BOARD= ../board_stm32f4_dis_bb 92 | 93 | # Startup files. 94 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk 95 | # HAL-OSAL files (optional). 96 | include $(CHIBIOS)/os/hal/hal.mk 97 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk 98 | include $(CHIBIOS)/os/hal/osal/rt/osal.mk 99 | # RTOS files (optional). 100 | include $(CHIBIOS)/os/rt/rt.mk 101 | include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk 102 | # Other files (optional). 103 | include $(BOARD)/board.mk 104 | include $(CHIBIOS)/os/various/lwip_bindings/lwip.mk 105 | 106 | 107 | # Define linker script file here 108 | LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld 109 | 110 | # C sources that can be compiled in ARM or THUMB mode depending on the global 111 | # setting. 112 | CSRC = $(STARTUPSRC) \ 113 | $(KERNSRC) \ 114 | $(PORTSRC) \ 115 | $(OSALSRC) \ 116 | $(HALSRC) \ 117 | $(PLATFORMSRC) \ 118 | $(BOARDSRC) \ 119 | $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ 120 | $(CHIBIOS)/os/various/evtimer.c \ 121 | $(CHIBIOS)/os/various/memstreams.c \ 122 | $(LWSRC) \ 123 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c \ 124 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c \ 125 | audio/audio_tx.c \ 126 | audio/autogen_fir_coeffs.c \ 127 | audio/audio_control_server.c \ 128 | rtp/rtp.c \ 129 | utils/debug.c \ 130 | mp45dt02_processing.c \ 131 | random/random.c \ 132 | main.c 133 | 134 | 135 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global 136 | # setting. 137 | CPPSRC = 138 | 139 | # C sources to be compiled in ARM mode regardless of the global setting. 140 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 141 | # option that results in lower performance and larger code size. 142 | ACSRC = 143 | 144 | # C++ sources to be compiled in ARM mode regardless of the global setting. 145 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 146 | # option that results in lower performance and larger code size. 147 | ACPPSRC = 148 | 149 | # C sources to be compiled in THUMB mode regardless of the global setting. 150 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 151 | # option that results in lower performance and larger code size. 152 | TCSRC = 153 | 154 | # C sources to be compiled in THUMB mode regardless of the global setting. 155 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 156 | # option that results in lower performance and larger code size. 157 | TCPPSRC = 158 | 159 | # List ASM source files here 160 | ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) 161 | 162 | INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ 163 | $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ 164 | $(CHIBIOS)/os/hal/lib/streams \ 165 | $(CHIBIOS)/os/various \ 166 | $(LWINC) \ 167 | $(CMSIS)/Include \ 168 | audio \ 169 | random \ 170 | rtp \ 171 | utils 172 | 173 | 174 | # 175 | # Project, sources and paths 176 | ############################################################################## 177 | 178 | ############################################################################## 179 | # Compiler settings 180 | # 181 | 182 | MCU = cortex-m4 183 | 184 | #TRGT = arm-elf- 185 | TRGT = arm-none-eabi- 186 | CC = $(TRGT)gcc 187 | CPPC = $(TRGT)g++ 188 | # Enable loading with g++ only if you need C++ runtime support. 189 | # NOTE: You can use C++ even without C++ support if you are careful. C++ 190 | # runtime support makes code size explode. 191 | LD = $(TRGT)gcc 192 | #LD = $(TRGT)g++ 193 | CP = $(TRGT)objcopy 194 | AS = $(TRGT)gcc -x assembler-with-cpp 195 | AR = $(TRGT)ar 196 | OD = $(TRGT)objdump 197 | SZ = $(TRGT)size 198 | HEX = $(CP) -O ihex 199 | BIN = $(CP) -O binary 200 | 201 | # ARM-specific options here 202 | AOPT = 203 | 204 | # THUMB-specific options here 205 | TOPT = -mthumb -DTHUMB 206 | 207 | # Define C warning options here 208 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes 209 | 210 | # Define C++ warning options here 211 | CPPWARN = -Wall -Wextra -Wundef 212 | 213 | # 214 | # Compiler settings 215 | ############################################################################## 216 | 217 | ############################################################################## 218 | # Start of user section 219 | # 220 | 221 | # List all user C define here, like -D_DEBUG=1 222 | # CMSIS 223 | UDEFS = -DARM_MATH_CM4 -D__FPU_PRESENT -DCHPRINTF_USE_FLOAT=1 224 | 225 | # Define ASM defines here 226 | UADEFS = 227 | 228 | # List all user directories here 229 | UINCDIR = 230 | 231 | # List the user directory to look for the libraries here 232 | ULIBDIR = 233 | 234 | # List all user libraries here 235 | ULIBS = 236 | 237 | # 238 | # End of user defines 239 | ############################################################################## 240 | 241 | RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC 242 | include $(RULESPATH)/rules.mk 243 | -------------------------------------------------------------------------------- /stm32_streaming/audio/audio_control_server.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "debug.h" 28 | 29 | #ifndef __AUDIO_CONTROL_SERVER_H__ 30 | #define __AUDIO_CONTROL_SERVER_H__ 31 | 32 | typedef struct { 33 | uint16_t localMgmtPort; 34 | uint16_t localAudioSourcePort; 35 | } AudioControlConfig; 36 | 37 | StatusCode audioControlInit(AudioControlConfig *config); 38 | StatusCode audioControlShutdown(void); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /stm32_streaming/audio/audio_tx.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef __AUDIO_TX_H__ 28 | #define __AUDIO_TX_H__ 29 | 30 | #include 31 | #include "lwip/ip_addr.h" 32 | 33 | typedef struct { 34 | ip_addr_t ipDest; 35 | uint16_t localRtpPort; 36 | uint16_t remoteRtpPort; 37 | } audioTxRtpConfig; 38 | 39 | void audioTxRtpSetup(audioTxRtpConfig *setupConfig); 40 | void audioTxRtpTeardown(void); 41 | void audioTxRtpPlay(void); 42 | void audioTxRtpPause(void); 43 | 44 | #endif /* Header Guard */ 45 | -------------------------------------------------------------------------------- /stm32_streaming/audio/autogen_fir_coeffs.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is an auto-generated file. 3 | 4 | Generated on: 2017-07-20 20:36 5 | 6 | Design Parameters: 7 | Sampling Frequency: 1024000.0 Hz 8 | Cutoff Frequency: 6000.0 Hz 9 | Taps: 256 10 | */ 11 | 12 | #include "autogen_fir_coeffs.h" 13 | 14 | float32_t firCoeffs[FIR_COEFFS_LEN] = { 15 | -0.00020365859931971167711, 16 | -0.00020534815286687269726, 17 | -0.00020750176033037726260, 18 | -0.00021012037631956283321, 19 | -0.00021319903662471212293, 20 | -0.00021672669737664450773, 21 | -0.00022068609510151509026, 22 | -0.00022505362843005770877, 23 | -0.00022979926215364830373, 24 | -0.00023488645424989164899, 25 | -0.00024027210642814768662, 26 | -0.00024590653867073892797, 27 | -0.00025173348816876021375, 28 | -0.00025769013297268373447, 29 | -0.00026370714059755645271, 30 | -0.00026970874174080279855, 31 | -0.00027561282918770678126, 32 | -0.00028133108189584986368, 33 | -0.00028676911416537141609, 34 | -0.00029182664971719136449, 35 | -0.00029639772041655876658, 36 | -0.00030037088929474201147, 37 | -0.00030362949743764215986, 38 | -0.00030605193422687278345, 39 | -0.00030751193033666963115, 40 | -0.00030787887280916823767, 41 | -0.00030701814145138336910, 42 | -0.00030479146571988795017, 43 | -0.00030105730118404599310, 44 | -0.00029567122458585908765, 45 | -0.00028848634644442410846, 46 | -0.00027935374008578901925, 47 | -0.00026812288591494918026, 48 | -0.00025464212968605439520, 49 | -0.00023875915346979392968, 50 | -0.00022032145796363610955, 51 | -0.00019917685474127628403, 52 | -0.00017517396699250889144, 53 | -0.00014816273726392078028, 54 | -0.00011799494067451189922, 55 | -0.00008452470204865435122, 56 | -0.00004760901538190323443, 57 | -0.00000710826403314813300, 58 | 0.00003711325998046934450, 59 | 0.00008518683922143004085, 60 | 0.00013723881824494437841, 61 | 0.00019339009683141017600, 62 | 0.00025375563067884116799, 63 | 0.00031844394118715329276, 64 | 0.00038755663595221715757, 65 | 0.00046118794156844918628, 66 | 0.00053942425031434893760, 67 | 0.00062234368226596488947, 68 | 0.00071001566434873101402, 69 | 0.00080250052779865996538, 70 | 0.00089984912545953673127, 71 | 0.00100210247029364294541, 72 | 0.00110929139642984651154, 73 | 0.00122143624401469842733, 74 | 0.00133854656906969905240, 75 | 0.00146062087949126880558, 76 | 0.00158764639825938126856, 77 | 0.00171959885484657777274, 78 | 0.00185644230574119823221, 79 | 0.00199812898491763665451, 80 | 0.00214459918500223235480, 81 | 0.00229578116979650909482, 82 | 0.00245159111872996935896, 83 | 0.00261193310372292942720, 84 | 0.00277669909884616615547, 85 | 0.00294576902306869798515, 86 | 0.00311901081628824334777, 87 | 0.00329628054874085653012, 88 | 0.00347742256378763981567, 89 | 0.00366226965397703886976, 90 | 0.00385064327018185947188, 91 | 0.00404235376351080345769, 92 | 0.00423720065959537831035, 93 | 0.00443497296475490934003, 94 | 0.00463544950344523757485, 95 | 0.00483839928630086513195, 96 | 0.00504358190798630257046, 97 | 0.00525074797398002775933, 98 | 0.00545963955532470946591, 99 | 0.00566999067028980431593, 100 | 0.00588152779180816168147, 101 | 0.00609397037946668093666, 102 | 0.00630703143475292229980, 103 | 0.00652041807818507478112, 104 | 0.00673383214688179267821, 105 | 0.00694697081106198169320, 106 | 0.00715952720790199309553, 107 | 0.00737119109112002388051, 108 | 0.00758164949460416685151, 109 | 0.00779058740835224944332, 110 | 0.00799768846494838640815, 111 | 0.00820263563476284277010, 112 | 0.00840511192802913253974, 113 | 0.00860480110192465494356, 114 | 0.00880138837075949628797, 115 | 0.00899456111736137396695, 116 | 0.00918400960373433675188, 117 | 0.00936942767906361571872, 118 | 0.00955051348313989967309, 119 | 0.00972697014328275690043, 120 | 0.00989850646285513405265, 121 | 0.01006483759947878094121, 122 | 0.01022568573108404224592, 123 | 0.01038078070795660050318, 124 | 0.01052986068897850992221, 125 | 0.01067267276030083034133, 126 | 0.01080897353473077651675, 127 | 0.01093852973016674022533, 128 | 0.01106111872547019779611, 129 | 0.01117652909222406794332, 130 | 0.01128456110089212129088, 131 | 0.01138502719996389682400, 132 | 0.01147775246674329584218, 133 | 0.01156257502851731552851, 134 | 0.01163934645292291625296, 135 | 0.01170793210641579012998, 136 | 0.01176821147983327271735, 137 | 0.01182007848013561825129, 138 | 0.01186344168750444287574, 139 | 0.01189822457707420330641, 140 | 0.01192436570467189822786, 141 | 0.01194181885604138869394, 142 | 0.01195055315913156820939, 143 | 0.01195055315913156820939, 144 | 0.01194181885604138869394, 145 | 0.01192436570467189822786, 146 | 0.01189822457707420330641, 147 | 0.01186344168750444287574, 148 | 0.01182007848013561825129, 149 | 0.01176821147983327271735, 150 | 0.01170793210641579012998, 151 | 0.01163934645292291625296, 152 | 0.01156257502851731379379, 153 | 0.01147775246674329584218, 154 | 0.01138502719996389508927, 155 | 0.01128456110089212129088, 156 | 0.01117652909222406794332, 157 | 0.01106111872547019779611, 158 | 0.01093852973016674022533, 159 | 0.01080897353473077651675, 160 | 0.01067267276030083034133, 161 | 0.01052986068897850992221, 162 | 0.01038078070795660050318, 163 | 0.01022568573108404051120, 164 | 0.01006483759947877920649, 165 | 0.00989850646285513231792, 166 | 0.00972697014328275516570, 167 | 0.00955051348313989620364, 168 | 0.00936942767906361224928, 169 | 0.00918400960373433675188, 170 | 0.00899456111736137396695, 171 | 0.00880138837075949628797, 172 | 0.00860480110192465320884, 173 | 0.00840511192802913080502, 174 | 0.00820263563476284277010, 175 | 0.00799768846494838467343, 176 | 0.00779058740835224944332, 177 | 0.00758164949460416511678, 178 | 0.00737119109112002301315, 179 | 0.00715952720790198875872, 180 | 0.00694697081106197909112, 181 | 0.00673383214688179094348, 182 | 0.00652041807818507304639, 183 | 0.00630703143475292056508, 184 | 0.00609397037946667833458, 185 | 0.00588152779180815907939, 186 | 0.00566999067028980171384, 187 | 0.00545963955532470773119, 188 | 0.00525074797398002428989, 189 | 0.00504358190798629996837, 190 | 0.00483839928630086252986, 191 | 0.00463544950344523584013, 192 | 0.00443497296475490934003, 193 | 0.00423720065959537744299, 194 | 0.00404235376351080259033, 195 | 0.00385064327018185860452, 196 | 0.00366226965397703756872, 197 | 0.00347742256378763851463, 198 | 0.00329628054874085522907, 199 | 0.00311901081628824248040, 200 | 0.00294576902306869711778, 201 | 0.00277669909884616442075, 202 | 0.00261193310372293029456, 203 | 0.00245159111872996935896, 204 | 0.00229578116979650909482, 205 | 0.00214459918500223192112, 206 | 0.00199812898491763622083, 207 | 0.00185644230574119779853, 208 | 0.00171959885484657712222, 209 | 0.00158764639825938061804, 210 | 0.00146062087949126793822, 211 | 0.00133854656906969818504, 212 | 0.00122143624401469734313, 213 | 0.00110929139642984672838, 214 | 0.00100210247029364316225, 215 | 0.00089984912545953694811, 216 | 0.00080250052779865996538, 217 | 0.00071001566434873101402, 218 | 0.00062234368226596488947, 219 | 0.00053942425031434872076, 220 | 0.00046118794156844907786, 221 | 0.00038755663595221694073, 222 | 0.00031844394118715313013, 223 | 0.00025375563067884133062, 224 | 0.00019339009683141025731, 225 | 0.00013723881824494443262, 226 | 0.00008518683922143004085, 227 | 0.00003711325998046934450, 228 | -0.00000710826403314813300, 229 | -0.00004760901538190322088, 230 | -0.00008452470204865435122, 231 | -0.00011799494067451185857, 232 | -0.00014816273726392067186, 233 | -0.00017517396699250878302, 234 | -0.00019917685474127644666, 235 | -0.00022032145796363627219, 236 | -0.00023875915346979398389, 237 | -0.00025464212968605450362, 238 | -0.00026812288591494923447, 239 | -0.00027935374008578907346, 240 | -0.00028848634644442410846, 241 | -0.00029567122458585908765, 242 | -0.00030105730118404599310, 243 | -0.00030479146571988795017, 244 | -0.00030701814145138293542, 245 | -0.00030787887280916807504, 246 | -0.00030751193033666941430, 247 | -0.00030605193422687256661, 248 | -0.00030362949743764178039, 249 | -0.00030037088929474163200, 250 | -0.00029639772041655854974, 251 | -0.00029182664971719098502, 252 | -0.00028676911416537103662, 253 | -0.00028133108189584943000, 254 | -0.00027561282918770634758, 255 | -0.00026970874174080236487, 256 | -0.00026370714059755645271, 257 | -0.00025769013297268357184, 258 | -0.00025173348816876005112, 259 | -0.00024590653867073892797, 260 | -0.00024027210642814755110, 261 | -0.00023488645424989151346, 262 | -0.00022979926215364816821, 263 | -0.00022505362843005757324, 264 | -0.00022068609510151495474, 265 | -0.00021672669737664431800, 266 | -0.00021319903662471212293, 267 | -0.00021012037631956283321, 268 | -0.00020750176033037726260, 269 | -0.00020534815286687269726, 270 | -0.00020365859931971167711, 271 | }; 272 | 273 | -------------------------------------------------------------------------------- /stm32_streaming/audio/autogen_fir_coeffs.h: -------------------------------------------------------------------------------- 1 | /* 2 | This is an auto-generated file. 3 | 4 | Generated on: 2017-07-20 20:36 5 | 6 | Design Parameters: 7 | Sampling Frequency: 1024000.0 Hz 8 | Cutoff Frequency: 6000.0 Hz 9 | Taps: 256 10 | */ 11 | 12 | #ifndef __AUTOGEN_FIR_COEFFS__ 13 | #define __AUTOGEN_FIR_COEFFS__ 14 | 15 | #include "arm_math.h" 16 | 17 | #define FIR_COEFFS_LEN 256 18 | extern float32_t firCoeffs[FIR_COEFFS_LEN]; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /stm32_streaming/audio/mp45dt02_processing.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef __MP45DT02_PDM_H__ 28 | #define __MP45DT02_PDM_H__ 29 | 30 | /* Number of times interrupts are called when filling the buffer. 31 | * ChibiOS fires twice half full / full */ 32 | #define MP45DT02_INTERRUPTS_PER_BUFFER 2 33 | 34 | /******************************************************************************/ 35 | /* Audio configuration */ 36 | /******************************************************************************/ 37 | /* Frequency at which the MP45DT02 is being (over) sampled. */ 38 | #define MP45DT02_RAW_FREQ_KHZ 1024 39 | 40 | /* One raw sample provided to processing.*/ 41 | #define MP45DT02_RAW_SAMPLE_DURATION_MS 1 42 | 43 | /******************************************************************************/ 44 | /* I2S Buffer - Contains 2 ms of sampled data. Emptied every 1ms */ 45 | /******************************************************************************/ 46 | 47 | /* The number of bits in I2S word */ 48 | #define MP45DT02_I2S_WORD_SIZE_BITS 16 49 | 50 | /* The number of PDM samples (bits) to process in one interrupt */ 51 | #define MP45DT02_I2S_SAMPLE_SIZE_BITS (MP45DT02_RAW_FREQ_KHZ * \ 52 | MP45DT02_RAW_SAMPLE_DURATION_MS) 53 | /* The length, in uint16_t's of the i2s buffer that will be filled per 54 | * interrupt. */ 55 | #define MP45DT02_I2S_SAMPLE_SIZE_2B (MP45DT02_I2S_SAMPLE_SIZE_BITS / \ 56 | MP45DT02_I2S_WORD_SIZE_BITS) 57 | /* The total required I2S buffer length. */ 58 | #define MP45DT02_I2S_BUFFER_SIZE_2B (MP45DT02_I2S_SAMPLE_SIZE_2B * \ 59 | MP45DT02_INTERRUPTS_PER_BUFFER) 60 | /******************************************************************************/ 61 | /* Expanded Buffer - 1 ms worth of 1 bit samples */ 62 | /******************************************************************************/ 63 | 64 | /* Every bit in I2S signal needs to be expanded out into a word. */ 65 | /* Note: I2S Interrupts are always fired at half/full buffer point. Thus 66 | * processed buffers require to be 0.5 * bits in one I2S buffer */ 67 | #define MP45DT02_EXPANDED_BUFFER_SIZE (MP45DT02_I2S_SAMPLE_SIZE_BITS) 68 | 69 | /******************************************************************************/ 70 | /* Decimated Buffer - 1 ms worth of processed audio data */ 71 | /******************************************************************************/ 72 | 73 | /* Desired decimation factor */ 74 | #define MP45DT02_FIR_DECIMATION_FACTOR 64 75 | 76 | /* Buffer size of the decimated sample */ 77 | #define MP45DT02_DECIMATED_BUFFER_SIZE (MP45DT02_EXPANDED_BUFFER_SIZE / \ 78 | MP45DT02_FIR_DECIMATION_FACTOR) 79 | 80 | typedef void (*mp45dt02FullBufferCb) (float *data, uint16_t length); 81 | 82 | typedef struct { 83 | /* Callback function to be notified when the processing buffer is full. */ 84 | mp45dt02FullBufferCb fullbufferCb; 85 | } mp45dt02Config; 86 | 87 | void mp45dt02Init(mp45dt02Config *config); 88 | void mp45dt02Shutdown(void); 89 | 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /stm32_streaming/config.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #ifndef __CONFIG_H__ 27 | #define __CONFIG_H__ 28 | 29 | #define IP(A,B,C,D) htonl(A<<24 | B<<16 | C<<8 | D) 30 | 31 | /******************************************************************************/ 32 | /* Board Networking Configuration */ 33 | /******************************************************************************/ 34 | 35 | /* The IP address of the board */ 36 | #define CONFIG_NET_IP_ADDR IP(192, 168, 1, 60) 37 | 38 | /* The available IP gateway of the board */ 39 | #define CONFIG_NET_IP_GATEWAY IP(192, 168, 1, 254) 40 | 41 | /* The subnet the board is attached to */ 42 | #define CONFIG_NET_IP_NETMASK IP(255, 255, 255, 0) 43 | 44 | /* MAC address of the board */ 45 | #define CONFIG_NET_ETH_ADDR_0 0xC2 46 | #define CONFIG_NET_ETH_ADDR_1 0xAF 47 | #define CONFIG_NET_ETH_ADDR_2 0x51 48 | #define CONFIG_NET_ETH_ADDR_3 0x03 49 | #define CONFIG_NET_ETH_ADDR_4 0xCF 50 | #define CONFIG_NET_ETH_ADDR_5 0x46 51 | 52 | /******************************************************************************/ 53 | /* Audio Streaming Configuration */ 54 | /******************************************************************************/ 55 | 56 | /* TCP port number to accept management connections on */ 57 | #define CONFIG_AUDIO_MGMT_PORT 20000 58 | 59 | /* UDP port number which will be the source of the audio stream */ 60 | #define CONFIG_AUDIO_SOURCE_PORT 40000 61 | 62 | 63 | #endif /* Header Guard */ 64 | -------------------------------------------------------------------------------- /stm32_streaming/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "ch.h" 29 | #include "hal.h" 30 | #include "debug.h" 31 | #include "lwipthread.h" 32 | #include "lwip/ip_addr.h" 33 | #include "lwip/api.h" 34 | #include "lwip/err.h" 35 | #include "random.h" 36 | #include "audio_control_server.h" 37 | #include "audio_tx.h" 38 | #include "config.h" 39 | 40 | static THD_WORKING_AREA(waBinkingThread, 128); 41 | 42 | static THD_FUNCTION(blinkingThread, arg) 43 | { 44 | (void)arg; 45 | chRegSetThreadName(__FUNCTION__); 46 | while (TRUE) 47 | { 48 | BOARD_LED_GREEN_TOGGLE(); 49 | chThdSleep(MS2ST(500)); 50 | } 51 | } 52 | 53 | int main(void) 54 | { 55 | AudioControlConfig audioControlConfig; 56 | struct lwipthread_opts opts; 57 | uint8_t optsMAC[6] = {CONFIG_NET_ETH_ADDR_0, 58 | CONFIG_NET_ETH_ADDR_1, 59 | CONFIG_NET_ETH_ADDR_2, 60 | CONFIG_NET_ETH_ADDR_3, 61 | CONFIG_NET_ETH_ADDR_4, 62 | CONFIG_NET_ETH_ADDR_5}; 63 | halInit(); 64 | chSysInit(); 65 | debugInit(); 66 | 67 | chThdCreateStatic(waBinkingThread, 68 | sizeof(waBinkingThread), 69 | LOWPRIO, 70 | blinkingThread, 71 | NULL); 72 | 73 | memset(&opts, 0, sizeof(opts)); 74 | opts.macaddress = optsMAC; 75 | opts.address = CONFIG_NET_IP_ADDR; 76 | opts.netmask = CONFIG_NET_IP_NETMASK; 77 | opts.gateway = CONFIG_NET_IP_GATEWAY; 78 | lwipInit(&opts); 79 | 80 | SC_ASSERT(randomInit()); 81 | 82 | while (macPollLinkStatus(ÐD1) == false) 83 | { 84 | chThdSleep(1); 85 | } 86 | 87 | memset(&audioControlConfig, 0, sizeof(audioControlConfig)); 88 | audioControlConfig.localAudioSourcePort = CONFIG_AUDIO_SOURCE_PORT; 89 | audioControlConfig.localMgmtPort = CONFIG_AUDIO_MGMT_PORT; 90 | SC_ASSERT(audioControlInit(&audioControlConfig)); 91 | 92 | PRINT("Device MAC: %02x:%02x:%02x:%02x:%02x:%02x", 93 | optsMAC[0], 94 | optsMAC[1], 95 | optsMAC[2], 96 | optsMAC[3], 97 | optsMAC[4], 98 | optsMAC[5]); 99 | PRINT("Device IP: %u.%u.%u.%u", 100 | ip4_addr1(&opts.address), 101 | ip4_addr2(&opts.address), 102 | ip4_addr3(&opts.address), 103 | ip4_addr4(&opts.address)); 104 | PRINT("Mgmt Port: %u", audioControlConfig.localMgmtPort); 105 | 106 | while (1) 107 | { 108 | chThdSleep(S2ST(1)); 109 | } 110 | 111 | return 0; 112 | } 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /stm32_streaming/random/random.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "ch.h" 28 | #include "hal.h" 29 | #include "random.h" 30 | 31 | /* Random numbers are generated after 40 cycles of the PLL48CLK - so the pool 32 | * doesn't have to be particularly big */ 33 | #define RANDOM_QUEUE_SIZE 4 34 | 35 | #define RNG_IRQ_VECTOR Vector180 36 | #define RNG_IRQ_POSITION 80 37 | #define RNG_IRQ_PRIORITY 15 38 | 39 | #define RANDOM_STATS 1 40 | 41 | static struct { 42 | 43 | struct { 44 | uint32_t q[RANDOM_QUEUE_SIZE]; 45 | uint32_t size; 46 | uint32_t *nextRead; 47 | uint32_t *nextWrite; 48 | mutex_t mutex; 49 | condition_variable_t conditionEmpty; 50 | } queue; 51 | 52 | #if RANDOM_STATS 53 | struct { 54 | uint32_t hwDataReady; 55 | uint32_t hwSeedErrors; 56 | uint32_t hwClockErrors; 57 | } stats; 58 | #endif 59 | 60 | } rngMgmt; 61 | 62 | /* Hash and Rng Global Interrupt */ 63 | CH_IRQ_HANDLER(RNG_IRQ_VECTOR) 64 | { 65 | CH_IRQ_PROLOGUE(); 66 | 67 | uint32_t random = 0; 68 | 69 | chSysLockFromISR(); 70 | 71 | if (RNG->SR & RNG_SR_DRDY) 72 | { 73 | #if RANDOM_STATS 74 | rngMgmt.stats.hwDataReady++; 75 | #endif 76 | random = RNG->DR; 77 | } 78 | 79 | if (RNG->SR & RNG_SR_CEIS) 80 | { 81 | #if RANDOM_STATS 82 | rngMgmt.stats.hwClockErrors++; 83 | #endif 84 | RNG->SR &= ~RNG_SR_CEIS; 85 | } 86 | 87 | if (RNG->SR & RNG_SR_SEIS) 88 | { 89 | #if RANDOM_STATS 90 | rngMgmt.stats.hwSeedErrors++; 91 | #endif 92 | 93 | RNG->SR &= ~RNG_SR_SEIS; 94 | 95 | /* Reinitialise the Random Number Generator and hopefully everything 96 | * will be OK. */ 97 | RNG->CR &= ~RNG_CR_RNGEN; 98 | RNG->CR |= RNG_CR_RNGEN; 99 | } 100 | 101 | else 102 | /* Only add the random number to the queue if not currently in error */ 103 | { 104 | if (rngMgmt.queue.size < RANDOM_QUEUE_SIZE) 105 | { 106 | *rngMgmt.queue.nextWrite = random; 107 | rngMgmt.queue.size++; 108 | 109 | if (++rngMgmt.queue.nextWrite == &rngMgmt.queue.q[RANDOM_QUEUE_SIZE]) 110 | { 111 | rngMgmt.queue.nextWrite = &rngMgmt.queue.q[0]; 112 | } 113 | 114 | chCondSignalI(&rngMgmt.queue.conditionEmpty); 115 | } 116 | 117 | if (rngMgmt.queue.size == RANDOM_QUEUE_SIZE) 118 | { 119 | /* If we have a full queue, stop interrupts for the time being. Note 120 | * by the time we get here there is likely already one more 121 | * interrupt ready to fire. */ 122 | RNG->CR &= ~RNG_CR_IE; 123 | } 124 | } 125 | 126 | chSysUnlockFromISR(); 127 | 128 | CH_IRQ_EPILOGUE(); 129 | } 130 | 131 | StatusCode randomInit(void) 132 | { 133 | chMtxObjectInit(&rngMgmt.queue.mutex); 134 | chCondObjectInit(&rngMgmt.queue.conditionEmpty); 135 | 136 | rngMgmt.queue.size = 0; 137 | rngMgmt.queue.nextWrite = &rngMgmt.queue.q[0]; 138 | rngMgmt.queue.nextRead = &rngMgmt.queue.q[0]; 139 | 140 | nvicEnableVector(RNG_IRQ_POSITION, RNG_IRQ_PRIORITY); 141 | 142 | RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; 143 | RNG->CR |= RNG_CR_RNGEN | RNG_CR_IE; 144 | 145 | return STATUS_OK; 146 | } 147 | 148 | StatusCode randomShutdown(void) 149 | { 150 | RNG->CR &= ~(RNG_CR_RNGEN | RNG_CR_IE); 151 | RCC->AHB2ENR &= ~RCC_AHB2ENR_RNGEN; 152 | 153 | return STATUS_OK; 154 | } 155 | 156 | StatusCode randomGet(uint32_t *random) 157 | { 158 | chSysLock(); 159 | chMtxLockS(&rngMgmt.queue.mutex); 160 | 161 | while (rngMgmt.queue.size == 0) 162 | { 163 | if (MSG_OK != chCondWaitTimeoutS(&rngMgmt.queue.conditionEmpty, 164 | ST2MS(25))) 165 | { 166 | chMtxUnlockS(&rngMgmt.queue.mutex); 167 | chSysUnlock(); 168 | return STATUS_ERROR_TIMEOUT; 169 | } 170 | } 171 | 172 | *random = *rngMgmt.queue.nextRead; 173 | rngMgmt.queue.size--; 174 | 175 | if (++rngMgmt.queue.nextRead == &rngMgmt.queue.q[RANDOM_QUEUE_SIZE]) 176 | { 177 | rngMgmt.queue.nextRead = &rngMgmt.queue.q[0]; 178 | } 179 | 180 | RNG->CR |= RNG_CR_IE; 181 | 182 | chMtxUnlockS(&rngMgmt.queue.mutex); 183 | chSysUnlock(); 184 | 185 | return STATUS_OK; 186 | } 187 | 188 | 189 | -------------------------------------------------------------------------------- /stm32_streaming/random/random.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef __RANDOM_H__ 28 | #define __RANDOM_H__ 29 | 30 | #include 31 | #include 32 | 33 | StatusCode randomInit(void); 34 | StatusCode randomShutdown(void); 35 | StatusCode randomGet(uint32_t *random); 36 | 37 | #endif /* Header Guard */ 38 | 39 | 40 | -------------------------------------------------------------------------------- /stm32_streaming/rtp/rtp.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include 28 | #include "rtp.h" 29 | 30 | #define RTP_VERSION 2 31 | 32 | #define HTON32(H32) (__builtin_bswap32(H32)) 33 | #define HTON16(H16) (__builtin_bswap16(H16)) 34 | 35 | #define COMPILE_ASSERT(EXPR) \ 36 | extern int (*compileAssert(void)) \ 37 | [sizeof(struct {unsigned int assert : (EXPR) ? 1 : -1;})] 38 | 39 | /* RTP data header on the wire */ 40 | typedef struct { 41 | /* 0 1 2 3 4 5 6 7 42 | *|V |P|X| CC | */ 43 | uint8_t verPadExCC; 44 | /* 0 1 2 3 4 5 6 7 45 | *|M| PT | */ 46 | uint8_t markerPayloadType; 47 | uint16_t sequenceNumber; 48 | uint32_t timestamp; 49 | uint32_t ssrc; 50 | uint32_t csrc[0]; 51 | } rtpDataHeader; 52 | 53 | COMPILE_ASSERT(sizeof(rtpDataHeader) == RTP_HEADER_LENGTH); 54 | 55 | static struct 56 | { 57 | rtpConfig config; 58 | 59 | /* Last transmitted sequence number in RTP */ 60 | uint16_t sequenceNumber; 61 | 62 | /* If RTP packets are generated periodically, the nominal sampling instant 63 | * as determined from the sampling clock is to be used, not a reading of the 64 | * system clock. */ 65 | uint32_t periodicTimestamp; 66 | 67 | uint32_t ssrc; 68 | 69 | } rtpDataStore; 70 | 71 | StatusCode rtpGetRand(uint32_t *random) 72 | { 73 | return rtpDataStore.config.getRandomCb(random); 74 | } 75 | 76 | StatusCode rtpInit(const rtpConfig *config) 77 | { 78 | StatusCode status = STATUS_ERROR_INTERNAL; 79 | uint32_t sequenceNumber = 0; 80 | 81 | if (config->getRandomCb == NULL) 82 | { 83 | return STATUS_ERROR_API; 84 | } 85 | 86 | memcpy(&rtpDataStore.config, config, sizeof(rtpDataStore.config)); 87 | 88 | if (STATUS_OK != (status = rtpGetRand(&rtpDataStore.ssrc))) 89 | { 90 | return status; 91 | } 92 | 93 | if (STATUS_OK != (status = rtpGetRand(&sequenceNumber))) 94 | { 95 | return status; 96 | } 97 | 98 | rtpDataStore.sequenceNumber = sequenceNumber; 99 | 100 | if (STATUS_OK != (status = rtpGetRand(&rtpDataStore.periodicTimestamp))) 101 | { 102 | return status; 103 | } 104 | 105 | return STATUS_OK; 106 | } 107 | 108 | StatusCode rtpShutdown(void) 109 | { 110 | memset(&rtpDataStore, 0, sizeof(rtpDataStore)); 111 | 112 | return STATUS_OK; 113 | } 114 | 115 | /* data should be a buffer with payload already in the correct place. */ 116 | StatusCode rtpAddHeader(uint8_t *data, 117 | uint32_t length) 118 | { 119 | rtpDataHeader *header = (rtpDataHeader*)data; 120 | 121 | if (data == NULL || length < RTP_HEADER_LENGTH) 122 | { 123 | return STATUS_ERROR_API; 124 | } 125 | 126 | rtpDataStore.periodicTimestamp += rtpDataStore.config.periodicTimestampIncr; 127 | rtpDataStore.sequenceNumber++; 128 | 129 | header->verPadExCC = RTP_VERSION << 6; 130 | header->markerPayloadType = rtpDataStore.config.payloadType; 131 | header->timestamp = HTON32(rtpDataStore.periodicTimestamp); 132 | header->sequenceNumber = HTON16(rtpDataStore.sequenceNumber); 133 | header->ssrc = HTON32(rtpDataStore.ssrc); 134 | 135 | return STATUS_OK; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /stm32_streaming/rtp/rtp.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef __RTP_H__ 28 | #define __RTP_H__ 29 | 30 | #include 31 | #include "debug.h" 32 | 33 | #define RTP_HEADER_LENGTH 12 34 | 35 | typedef StatusCode (*rtpGetRandom)(uint32_t *random); 36 | 37 | typedef struct { 38 | /* Value to increment the period time stamp by per RTP packet 39 | * transmitted */ 40 | uint32_t periodicTimestampIncr; 41 | /* Payload type of RTP packet */ 42 | uint8_t payloadType; 43 | /* Callback to obtain random numbers */ 44 | rtpGetRandom getRandomCb; 45 | } rtpConfig; 46 | 47 | 48 | /******************************************************************************/ 49 | 50 | StatusCode rtpInit(const rtpConfig *config); 51 | StatusCode rtpShutdown(void); 52 | StatusCode rtpAddHeader(uint8_t *data, 53 | uint32_t length); 54 | 55 | #endif /* Header Guard */ 56 | -------------------------------------------------------------------------------- /stm32_streaming/utils/debug.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #include "ch.h" 27 | #include "hal.h" 28 | #include "chprintf.h" 29 | #include "debug.h" 30 | 31 | #define SERIAL_PRINT_DRIVER SD1 32 | 33 | mutex_t serialPrintMtx; 34 | 35 | static const char *statusCodeString[] = { 36 | "STATUS_OK", 37 | "STATUS_ERROR_API", 38 | "STATUS_ERROR_CALLBACK", 39 | "STATUS_ERROR_INTERNAL", 40 | "STATUS_ERROR_EXTERNAL_INPUT", 41 | "STATUS_ERROR_OS", 42 | "STATUS_ERROR_LIBRARY", 43 | "STATUS_ERROR_LIBRARY_LWIP", 44 | "STATUS_ERROR_HW", 45 | "STATUS_ERROR_TIMEOUT", 46 | "STATUS_CODE_ENUM_MAX" 47 | }; 48 | 49 | const char* statusCodeToString(StatusCode code) 50 | { 51 | if (code > (STATUS_CODE_ENUM_MAX)) 52 | { 53 | return "UNKNOWN STATUS CODE"; 54 | } 55 | 56 | return statusCodeString[code]; 57 | } 58 | 59 | void debugInit(void) 60 | { 61 | /* Configure Debug Serial */ 62 | sdStart(&SERIAL_PRINT_DRIVER, NULL); 63 | palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(7)); 64 | palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(7)); 65 | chMtxObjectInit(&serialPrintMtx); 66 | } 67 | 68 | void debugShutdown(void) 69 | { 70 | sdStop(&SERIAL_PRINT_DRIVER); 71 | } 72 | 73 | void debugSerialPrintVa(const char *fmt, va_list argList) 74 | { 75 | chMtxLock(&serialPrintMtx); 76 | chvprintf((BaseSequentialStream*)&SERIAL_PRINT_DRIVER, fmt, argList); 77 | chMtxUnlock(&serialPrintMtx); 78 | } 79 | 80 | void debugSerialPrint(const char *fmt, ...) 81 | { 82 | va_list argList; 83 | va_start(argList, fmt); 84 | debugSerialPrintVa(fmt, argList); 85 | va_end(argList); 86 | } 87 | 88 | void HardFault_Handler(void) 89 | { 90 | BOARD_LED_RED_SET(); 91 | while (true); 92 | } 93 | 94 | void MemManage_Handler(void) 95 | { 96 | BOARD_LED_RED_SET(); 97 | while (true); 98 | } 99 | 100 | void BusFault_Handler(void) 101 | { 102 | BOARD_LED_RED_SET(); 103 | while (true); 104 | } 105 | 106 | void UsageFault_Handler(void) 107 | { 108 | BOARD_LED_RED_SET(); 109 | while (true); 110 | } 111 | 112 | void DebugMon_Handler(void) 113 | { 114 | BOARD_LED_RED_SET(); 115 | while (true); 116 | } 117 | -------------------------------------------------------------------------------- /stm32_streaming/utils/debug.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #ifndef _DEBUG_H_ 27 | #define _DEBUG_H_ 28 | 29 | #include "ch.h" 30 | #include "hal.h" 31 | #include 32 | 33 | #if 1 34 | #define PRINT(FMT, ...) \ 35 | debugSerialPrint("(%s:%d) " FMT "\n\r", __FILE__, __LINE__, __VA_ARGS__) 36 | 37 | #else 38 | #define PRINT(FMT, ...) 39 | #endif 40 | 41 | #define PRINT_CRITICAL(FMT, ...)\ 42 | PRINT("ERROR: " FMT, __VA_ARGS__); \ 43 | \ 44 | while (1) \ 45 | { \ 46 | BOARD_LED_RED_SET(); \ 47 | chThdSleepMilliseconds(500); \ 48 | BOARD_LED_RED_CLEAR(); \ 49 | chThdSleepMilliseconds(500); \ 50 | BOARD_LED_RED_SET(); \ 51 | chSysHalt("ERROR"); \ 52 | } 53 | 54 | #define SC_ASSERT(FUNC_CALL) \ 55 | { \ 56 | StatusCode _sc = FUNC_CALL; \ 57 | if (_sc != STATUS_OK) \ 58 | { \ 59 | PRINT("Error: %s", statusCodeToString(_sc)); \ 60 | return _sc; \ 61 | } \ 62 | } 63 | 64 | #define SC_ASSERT_MSG(FUNC_CALL, FMT, ...) \ 65 | { \ 66 | StatusCode _sc = FUNC_CALL; \ 67 | if (_sc != STATUS_OK) \ 68 | { \ 69 | PRINT("Error: " FMT, __VA_ARGS__); \ 70 | PRINT("Error: %s.", statusCodeToString(_sc)); \ 71 | return _sc; \ 72 | } \ 73 | } 74 | 75 | extern mutex_t serialPrintMtx; 76 | 77 | typedef enum 78 | { 79 | /* Success */ 80 | STATUS_OK, 81 | /* Argument provided to API was bad */ 82 | STATUS_ERROR_API, 83 | /* Callback failed */ 84 | STATUS_ERROR_CALLBACK, 85 | /* Internal error */ 86 | STATUS_ERROR_INTERNAL, 87 | /* Some form of system input was out of expected range. */ 88 | STATUS_ERROR_EXTERNAL_INPUT, 89 | /* OS returned Error */ 90 | STATUS_ERROR_OS, 91 | /* Library returned error */ 92 | STATUS_ERROR_LIBRARY, 93 | /* LWIP Library returned error */ 94 | STATUS_ERROR_LIBRARY_LWIP, 95 | /* Error interfacing with HW */ 96 | STATUS_ERROR_HW, 97 | /* Unexpected timeout */ 98 | STATUS_ERROR_TIMEOUT, 99 | /* Placeholder for bounds checking */ 100 | STATUS_CODE_ENUM_MAX 101 | } StatusCode; 102 | 103 | 104 | void debugInit(void); 105 | void debugShutdown(void); 106 | void debugSerialPrint(const char * fmt, ...); 107 | void debugSerialPrintVa(const char *fmt, va_list argList); 108 | const char* statusCodeToString(StatusCode code); 109 | 110 | #endif /* Header Guard*/ 111 | -------------------------------------------------------------------------------- /test/cmsis_fir_filters/README.md: -------------------------------------------------------------------------------- 1 | # CMSIS FIR Filtering Function Comparison 2 | 3 | The files here to produce a crude comparison of CMSIS DSP FIR filtering 4 | functions. The steps required to run this test are listed below. 5 | 6 | You can see a write up of this test at: 7 | [www.theunterminatedstring.com/cmsis-arm-fir-comparison](http://www.theunterminatedstring.com/cmsis-arm-fir-comparison). 8 | 9 | Note: The comparisons made by these scripts are very rough, and are intended to 10 | provide a ballpark figure. For instance, there are some accuracy issues with how 11 | floating point numbers are being pulled from GDB. 12 | 13 | To generate the FIR filter coefficients and test signal the following 14 | dependancies will need to be met: 15 | * Python (version 2) 16 | * NumPy 17 | * SciPy 18 | * matplotlib. 19 | 20 | You hopefully should be able to obtain these with ease via your package manager 21 | (GNU/Linux assumed). Alternatively, [Sage Math](http://www.sagemath.org/), 22 | provides them, packaged up along with other related tools. 23 | 24 | ## Create FIR Filter 25 | 26 | The file `utils/design.py`, when executed, produces: 27 | * FIR filter coefficients 28 | * a test signal 29 | * the expected filtered signal 30 | * some plots of the FIR filter response and signal. 31 | 32 | The output of this script can be found in `output/design/`. This directory 33 | structure will be created relative to where this file was executed. 34 | 35 | The auto-generated C files, found in `output/design/files` need to be moved to 36 | `src/`. 37 | 38 | The generated plots and be viewed in `output/design/plots`, if so desired. 39 | 40 | ## Make & Execute on MCU 41 | 42 | With the output of design.py, all the files required to run the test against a 43 | STM32F4DISCOVERY (STM32F407) should now be present. 44 | Optimised and unoptimised performance of the CMSIS filter functions was of 45 | interest to me so to reproduce this, this step will need to be repeated. The 46 | variable `USE_OPT` in `src/Makefile` should be altered as appropriate between 47 | runs, and the log file name changes as appropriate. The names I used can be seen 48 | sequentially in the command list below (obviously the last call of `set logging 49 | file` will set the log file to be used). 50 | 51 | Once the program has been built and executed to completion on the MCU, the 52 | GDB commands listed below will retrieve the required data for comparison. 53 | 54 | ### GDB Commands 55 | 56 | set height 0 57 | set print elements 0 58 | set print array on 59 | set logging file gdb_data_out_unopt.txt 60 | set logging file gdb_data_out_opt.txt 61 | set logging overwrite on 62 | set logging on 63 | print convertedOutput 64 | print time 65 | set logging off 66 | 67 | 68 | ## Comparison 69 | 70 | The script `utils/compare.py` can now be run to perform the comparison 71 | of the expected filtered signal as calculated by Python, and the various 72 | filtered signals calculated by CMSIS on the MCU. This script requires several 73 | arguments, which are described in the file itself. 74 | 75 | The output of this script is directed towards `output/comparison/`, relative to 76 | where it was executed. 77 | 78 | -------------------------------------------------------------------------------- /test/cmsis_fir_filters/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build global options 3 | # NOTE: Can be overridden externally. 4 | # 5 | 6 | # Compiler options here. 7 | ifeq ($(USE_OPT),) 8 | USE_OPT = -O2 -ggdb3 -fomit-frame-pointer -falign-functions=16 9 | USE_OPT = -O0 -ggdb3 -fomit-frame-pointer -falign-functions=16 10 | # -O2 changes the output of calculated floating point values. This appears to 11 | # be at least partly to blame - disabling this gives consistant output. 12 | #USE_OPT += -fno-expensive-optimizations 13 | 14 | endif 15 | 16 | # C specific options here (added to USE_OPT). 17 | ifeq ($(USE_COPT),) 18 | USE_COPT = 19 | endif 20 | 21 | # C++ specific options here (added to USE_OPT). 22 | ifeq ($(USE_CPPOPT),) 23 | USE_CPPOPT = -fno-rtti 24 | endif 25 | 26 | # Enable this if you want the linker to remove unused code and data 27 | ifeq ($(USE_LINK_GC),) 28 | USE_LINK_GC = yes 29 | endif 30 | 31 | # Linker extra options here. 32 | ifeq ($(USE_LDOPT),) 33 | USE_LDOPT = 34 | endif 35 | 36 | # Enable this if you want link time optimizations (LTO) 37 | ifeq ($(USE_LTO),) 38 | USE_LTO = no 39 | endif 40 | 41 | # If enabled, this option allows to compile the application in THUMB mode. 42 | ifeq ($(USE_THUMB),) 43 | USE_THUMB = yes 44 | endif 45 | 46 | # Enable this if you want to see the full log while compiling. 47 | ifeq ($(USE_VERBOSE_COMPILE),) 48 | USE_VERBOSE_COMPILE = no 49 | endif 50 | 51 | # If enabled, this option makes the build process faster by not compiling 52 | # modules not used in the current configuration. 53 | ifeq ($(USE_SMART_BUILD),) 54 | USE_SMART_BUILD = yes 55 | endif 56 | 57 | # 58 | # Build global options 59 | ############################################################################## 60 | 61 | ############################################################################## 62 | # Architecture or project specific options 63 | # 64 | 65 | # Stack size to be allocated to the Cortex-M process stack. This stack is 66 | # the stack used by the main() thread. 67 | ifeq ($(USE_PROCESS_STACKSIZE),) 68 | USE_PROCESS_STACKSIZE = 0x400 69 | endif 70 | 71 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This 72 | # stack is used for processing interrupts and exceptions. 73 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) 74 | USE_EXCEPTIONS_STACKSIZE = 0x400 75 | endif 76 | 77 | # Enables the use of FPU on Cortex-M4 (no, softfp, hard). 78 | ifeq ($(USE_FPU),) 79 | USE_FPU = hard 80 | endif 81 | 82 | # 83 | # Architecture or project specific options 84 | ############################################################################## 85 | 86 | ############################################################################## 87 | # Project, sources and paths 88 | # 89 | 90 | # Define project name here 91 | PROJECT = test 92 | 93 | # Imported source files and paths 94 | CHIBIOS = ../../../lib/ChibiOS 95 | CMSIS= ../../../lib/CMSIS/CMSIS 96 | BOARD= ../../../board_stm32f4_dis_bb 97 | 98 | # Startup files. 99 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk 100 | # HAL-OSAL files (optional). 101 | include $(CHIBIOS)/os/hal/hal.mk 102 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk 103 | include $(CHIBIOS)/os/hal/osal/rt/osal.mk 104 | # RTOS files (optional). 105 | include $(CHIBIOS)/os/rt/rt.mk 106 | include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk 107 | # Other files (optional). 108 | include $(BOARD)/board.mk 109 | 110 | # Define linker script file here 111 | LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld 112 | 113 | # C sources that can be compiled in ARM or THUMB mode depending on the global 114 | # setting. 115 | CSRC = $(STARTUPSRC) \ 116 | $(KERNSRC) \ 117 | $(PORTSRC) \ 118 | $(OSALSRC) \ 119 | $(HALSRC) \ 120 | $(PLATFORMSRC) \ 121 | $(BOARDSRC) \ 122 | $(TESTSRC) \ 123 | $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ 124 | $(CHIBIOS)/os/various/evtimer.c \ 125 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c \ 126 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c \ 127 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_f32.c \ 128 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_f32.c \ 129 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q31.c \ 130 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q31.c \ 131 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q31.c \ 132 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q15.c \ 133 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q15.c \ 134 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q15.c \ 135 | $(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q31.c \ 136 | $(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q15.c \ 137 | $(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_float.c \ 138 | $(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_float.c \ 139 | autogen_fir_coeff.c \ 140 | main.c \ 141 | 142 | 143 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global 144 | # setting. 145 | CPPSRC = 146 | 147 | # C sources to be compiled in ARM mode regardless of the global setting. 148 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 149 | # option that results in lower performance and larger code size. 150 | ACSRC = 151 | 152 | # C++ sources to be compiled in ARM mode regardless of the global setting. 153 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 154 | # option that results in lower performance and larger code size. 155 | ACPPSRC = 156 | 157 | # C sources to be compiled in THUMB mode regardless of the global setting. 158 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 159 | # option that results in lower performance and larger code size. 160 | TCSRC = 161 | 162 | # C sources to be compiled in THUMB mode regardless of the global setting. 163 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 164 | # option that results in lower performance and larger code size. 165 | TCPPSRC = 166 | 167 | # List ASM source files here 168 | ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) 169 | 170 | INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ 171 | $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ 172 | $(CHIBIOS)/os/hal/lib/streams \ 173 | $(CHIBIOS)/os/various \ 174 | $(CMSIS)/Include 175 | 176 | # 177 | # Project, sources and paths 178 | ############################################################################## 179 | 180 | ############################################################################## 181 | # Compiler settings 182 | # 183 | 184 | MCU = cortex-m4 185 | 186 | #TRGT = arm-elf- 187 | TRGT = arm-none-eabi- 188 | CC = $(TRGT)gcc 189 | CPPC = $(TRGT)g++ 190 | # Enable loading with g++ only if you need C++ runtime support. 191 | # NOTE: You can use C++ even without C++ support if you are careful. C++ 192 | # runtime support makes code size explode. 193 | LD = $(TRGT)gcc 194 | #LD = $(TRGT)g++ 195 | CP = $(TRGT)objcopy 196 | AS = $(TRGT)gcc -x assembler-with-cpp 197 | AR = $(TRGT)ar 198 | OD = $(TRGT)objdump 199 | SZ = $(TRGT)size 200 | HEX = $(CP) -O ihex 201 | BIN = $(CP) -O binary 202 | 203 | # ARM-specific options here 204 | AOPT = 205 | 206 | # THUMB-specific options here 207 | TOPT = -mthumb -DTHUMB 208 | 209 | # Define C warning options here 210 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes 211 | 212 | # Define C++ warning options here 213 | CPPWARN = -Wall -Wextra -Wundef 214 | 215 | # 216 | # Compiler settings 217 | ############################################################################## 218 | 219 | ############################################################################## 220 | # Start of user section 221 | # 222 | 223 | # List all user C define here, like -D_DEBUG=1 224 | # CMSIS 225 | UDEFS = -DARM_MATH_CM4 -D__FPU_PRESENT -DCHPRINTF_USE_FLOAT=1 226 | 227 | # Define ASM defines here 228 | UADEFS = 229 | 230 | # List all user directories here 231 | UINCDIR = 232 | 233 | # List the user directory to look for the libraries here 234 | ULIBDIR = 235 | 236 | # List all user libraries here 237 | ULIBS = 238 | 239 | # 240 | # End of user defines 241 | ############################################################################## 242 | 243 | RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC 244 | include $(RULESPATH)/rules.mk 245 | -------------------------------------------------------------------------------- /test/cmsis_fir_filters/utils/design.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2016, Alan Barr 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # * Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # * Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | ################################################################################ 26 | 27 | import numpy as np 28 | import os 29 | from scipy import signal as signal 30 | from scipy.fftpack import fft 31 | import matplotlib.pyplot as plot 32 | 33 | ################################################################################ 34 | ##### Configuration ##### 35 | ################################################################################ 36 | 37 | np.random.seed(42) 38 | 39 | dir_text = "./output/design/files/" 40 | dir_plots = "./output/design/plots/" 41 | 42 | file_c_coeff = "autogen_fir_coeff" 43 | 44 | # Sampling frequency, Hz 45 | sampling_f = 16000.0 46 | # Cutoff frequency, Hz 47 | cutoff_f = 6000.0 48 | # Number of taps/ coefficients for FIR filter. (Order + 1) 49 | taps_n = 128 50 | # The number of samples to put into a test signal. 51 | samples_n = int(sampling_f / 10) # 100 ms worth of samples 52 | # Number of samples to be processed at once (used for generated C file.) 53 | block_n = 64 54 | 55 | ################################################################################ 56 | ##### Setup ##### 57 | ################################################################################ 58 | 59 | nyquist_f = sampling_f / 2.0 60 | 61 | if dir_plots and not os.path.exists(dir_plots): 62 | os.makedirs(dir_plots) 63 | 64 | ################################################################################ 65 | ##### Create signal, scaled between -1 and 1 ##### 66 | ################################################################################ 67 | 68 | t = np.arange(samples_n) / sampling_f 69 | 70 | x = 1.0 * np.cos(t*2*np.pi*500) + \ 71 | 1.0 * np.cos(t*2*np.pi*3000) + \ 72 | 1.0 * np.cos(t*2*np.pi*6060) + \ 73 | 1.0 * np.cos(t*2*np.pi*7000) 74 | 75 | x += np.random.normal(0, 0.30, samples_n) 76 | 77 | x = x / max(abs(x)) 78 | 79 | plot.figure() 80 | plot.plot(x) 81 | plot.grid() 82 | plot.title("Test Signal") 83 | plot.xlabel("Sample Number") 84 | plot.ylabel("Amplitude") 85 | plot.savefig(dir_plots + "1_x_signal.png") 86 | plot.close() 87 | 88 | ################################################################################ 89 | ##### FFT the created signal ##### 90 | ################################################################################ 91 | 92 | fft_x = fft(x, sampling_f) 93 | 94 | plot.figure() 95 | plot.plot(np.abs(fft_x[0:len(fft_x)/2])) 96 | plot.grid() 97 | plot.title("FFT of Test Signal") 98 | plot.xlabel("Frequency [Hz]") 99 | plot.ylabel("Power") 100 | plot.savefig(dir_plots + "2_x_signal_fft.png") 101 | plot.close() 102 | 103 | ################################################################################ 104 | ##### Create FIR ##### 105 | ################################################################################ 106 | 107 | fir_coeff = signal.firwin(taps_n, cutoff=cutoff_f, nyq = nyquist_f) 108 | 109 | w, h = signal.freqz(fir_coeff) 110 | 111 | unnormalised_f = w * nyquist_f/np.pi 112 | 113 | fig, ax1 = plot.subplots() 114 | plot.title('FIR Response') 115 | 116 | ax1.plot(unnormalised_f, 20 * np.log10(abs(h)), 'b') 117 | ax1.set_ylabel('Amplitude [dB]', color='b') 118 | for tl in ax1.get_yticklabels(): 119 | tl.set_color('b') 120 | 121 | ax2 = ax1.twinx() 122 | ax2.plot(unnormalised_f, np.unwrap(np.angle(h)), 'g') 123 | ax2.set_ylabel('Angle [radians]', color='g') 124 | for tl in ax2.get_yticklabels(): 125 | tl.set_color('g') 126 | 127 | ax1.set_xlabel('Frequency [Hz]') 128 | 129 | plot.grid() 130 | plot.axis('tight') 131 | plot.savefig(dir_plots + "3_fir.png") 132 | plot.close() 133 | 134 | ################################################################################ 135 | ##### Create FIR C Files ##### 136 | ################################################################################ 137 | 138 | fir_coeff_reversed = fir_coeff[::-1] 139 | 140 | if not os.path.exists(dir_text): 141 | os.makedirs(dir_text) 142 | 143 | # Header File 144 | h_file_handle = open(dir_text + file_c_coeff + ".h","w") 145 | 146 | h_file_handle.write("/* This is an auto-generated file. */\n\n") 147 | h_file_handle.write("#ifndef __%s__\n" %file_c_coeff.upper()) 148 | h_file_handle.write("#define __%s__\n\n" %file_c_coeff.upper()) 149 | 150 | h_file_handle.write("#define TEST_FIR_DATA_TYPE_BLOCK_LEN %s\n" %block_n) 151 | h_file_handle.write("#define TEST_FIR_DATA_TYPE_TAP_LEN %s\n" %taps_n) 152 | h_file_handle.write("#define TEST_FIR_DATA_TYPE_SIGNAL_LEN %s\n\n" %samples_n) 153 | 154 | h_file_handle.write("extern float testSignalFloat[%s];\n" %samples_n) 155 | h_file_handle.write("extern float armFirCoeffFloat[%s];\n" %taps_n) 156 | 157 | h_file_handle.write("\n#endif\n") 158 | h_file_handle.close() 159 | 160 | # C File 161 | file_handle = open(dir_text + file_c_coeff + ".c","w") 162 | file_handle.write("/* This is an auto-generated file. */\n\n") 163 | file_handle.write("#include \"arm_math.h\"\n\n") 164 | 165 | # Signal 166 | file_handle.write("float testSignalFloat[" + str(samples_n) + "] = {\n") 167 | for s in x: 168 | file_handle.write(" %.23f,\n" %s) 169 | file_handle.write("};\n\n") 170 | 171 | # Float Coeffs 172 | file_handle.write("float armFirCoeffFloat[" + str(taps_n) + "] = {\n") 173 | for f in fir_coeff_reversed: 174 | file_handle.write(" %.23f,\n" %f) 175 | file_handle.write("};\n\n") 176 | 177 | file_handle.close() 178 | 179 | ################################################################################ 180 | ##### FIR the Created Signal ##### 181 | ################################################################################ 182 | 183 | x_filtered = signal.lfilter(fir_coeff, [1], x) 184 | 185 | f_expected_signal = open(dir_text + "expected_signal.txt","w") 186 | 187 | for s in x_filtered: 188 | f_expected_signal.write("%.23f\n" %s) 189 | 190 | f_expected_signal.close() 191 | 192 | fft_x_filtered = fft(x_filtered, sampling_f) 193 | 194 | plot.plot(abs(fft_x_filtered[0:len(fft_x_filtered)/2])) 195 | plot.grid() 196 | plot.title("FFT of Filtered Test Signal") 197 | plot.xlabel("Frequency [Hz]") 198 | plot.ylabel("Power") 199 | plot.savefig(dir_plots + "4_x_signal_filtered_fft.png") 200 | plot.close() 201 | 202 | 203 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/README.md: -------------------------------------------------------------------------------- 1 | # LWIP UDP Echo Test 2 | 3 | This is a very crude test to prove LWIP is working. 4 | 5 | This test creates a simple UDP echo server on the board - any UDP packet 6 | received by the server will be echoed back to the sender. 7 | 8 | The IP configuration of the server can be configured at the top of src/lan8720.c 9 | 10 | The Python script, utils/udp_max_throughput_tester.py, can be used to provide a 11 | rough UDP throughput calculation against the echo server. 12 | Pass in --help for details on the required arguments. 13 | 14 | ## Extracting LWIP 15 | 16 | To build this project, the LWIP source code should first be extracted from the 17 | ChibiOS repository. 18 | 19 | Assuming the current working directory is with this README.md, issue the 20 | following commands to extract LWIP (assuming 7z is available on your system). 21 | 22 | cd ../../lib/ChibiOS/ext 23 | 7z x lwip-1.4.1_patched.7z 24 | cd - 25 | 26 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build global options 3 | # NOTE: Can be overridden externally. 4 | # 5 | 6 | # Compiler options here. 7 | ifeq ($(USE_OPT),) 8 | USE_OPT = -O0 -ggdb3 -fomit-frame-pointer -falign-functions=16 9 | endif 10 | 11 | # C specific options here (added to USE_OPT). 12 | ifeq ($(USE_COPT),) 13 | USE_COPT = 14 | endif 15 | 16 | # C++ specific options here (added to USE_OPT). 17 | ifeq ($(USE_CPPOPT),) 18 | USE_CPPOPT = -fno-rtti 19 | endif 20 | 21 | # Enable this if you want the linker to remove unused code and data 22 | ifeq ($(USE_LINK_GC),) 23 | USE_LINK_GC = yes 24 | endif 25 | 26 | # Linker extra options here. 27 | ifeq ($(USE_LDOPT),) 28 | USE_LDOPT = 29 | endif 30 | 31 | # Enable this if you want link time optimizations (LTO) 32 | ifeq ($(USE_LTO),) 33 | USE_LTO = no 34 | endif 35 | 36 | # If enabled, this option allows to compile the application in THUMB mode. 37 | ifeq ($(USE_THUMB),) 38 | USE_THUMB = yes 39 | endif 40 | 41 | # Enable this if you want to see the full log while compiling. 42 | ifeq ($(USE_VERBOSE_COMPILE),) 43 | USE_VERBOSE_COMPILE = no 44 | endif 45 | 46 | # If enabled, this option makes the build process faster by not compiling 47 | # modules not used in the current configuration. 48 | ifeq ($(USE_SMART_BUILD),) 49 | USE_SMART_BUILD = yes 50 | endif 51 | 52 | # 53 | # Build global options 54 | ############################################################################## 55 | 56 | ############################################################################## 57 | # Architecture or project specific options 58 | # 59 | 60 | # Stack size to be allocated to the Cortex-M process stack. This stack is 61 | # the stack used by the main() thread. 62 | ifeq ($(USE_PROCESS_STACKSIZE),) 63 | USE_PROCESS_STACKSIZE = 0x400 64 | endif 65 | 66 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This 67 | # stack is used for processing interrupts and exceptions. 68 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) 69 | USE_EXCEPTIONS_STACKSIZE = 0x400 70 | endif 71 | 72 | # Enables the use of FPU on Cortex-M4 (no, softfp, hard). 73 | ifeq ($(USE_FPU),) 74 | USE_FPU = hard 75 | endif 76 | 77 | # 78 | # Architecture or project specific options 79 | ############################################################################## 80 | 81 | ############################################################################## 82 | # Project, sources and paths 83 | # 84 | 85 | # Define project name here 86 | PROJECT = test 87 | 88 | # Imported source files and paths 89 | CHIBIOS = ../../../lib/ChibiOS 90 | CMSIS= ../../../lib/CMSIS/CMSIS 91 | BOARD= ../../../board_stm32f4_dis_bb 92 | 93 | # Startup files. 94 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk 95 | # HAL-OSAL files (optional). 96 | include $(CHIBIOS)/os/hal/hal.mk 97 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk 98 | include $(CHIBIOS)/os/hal/osal/rt/osal.mk 99 | # RTOS files (optional). 100 | include $(CHIBIOS)/os/rt/rt.mk 101 | include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk 102 | # Other files (optional). 103 | include $(CHIBIOS)/os/various/lwip_bindings/lwip.mk 104 | include $(BOARD)/board.mk 105 | 106 | # Define linker script file here 107 | LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld 108 | 109 | # C sources that can be compiled in ARM or THUMB mode depending on the global 110 | # setting. 111 | CSRC = $(STARTUPSRC) \ 112 | $(KERNSRC) \ 113 | $(PORTSRC) \ 114 | $(OSALSRC) \ 115 | $(HALSRC) \ 116 | $(PLATFORMSRC) \ 117 | $(BOARDSRC) \ 118 | $(TESTSRC) \ 119 | $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ 120 | $(CHIBIOS)/os/various/evtimer.c \ 121 | $(LWSRC) \ 122 | main.c \ 123 | lan8720.c 124 | 125 | 126 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global 127 | # setting. 128 | CPPSRC = 129 | 130 | # C sources to be compiled in ARM mode regardless of the global setting. 131 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 132 | # option that results in lower performance and larger code size. 133 | ACSRC = 134 | 135 | # C++ sources to be compiled in ARM mode regardless of the global setting. 136 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 137 | # option that results in lower performance and larger code size. 138 | ACPPSRC = 139 | 140 | # C sources to be compiled in THUMB mode regardless of the global setting. 141 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 142 | # option that results in lower performance and larger code size. 143 | TCSRC = 144 | 145 | # C sources to be compiled in THUMB mode regardless of the global setting. 146 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 147 | # option that results in lower performance and larger code size. 148 | TCPPSRC = 149 | 150 | # List ASM source files here 151 | ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) 152 | 153 | INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ 154 | $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ 155 | $(CHIBIOS)/os/hal/lib/streams \ 156 | $(CHIBIOS)/os/various \ 157 | $(LWINC) \ 158 | $(CMSIS)/Include 159 | 160 | # 161 | # Project, sources and paths 162 | ############################################################################## 163 | 164 | ############################################################################## 165 | # Compiler settings 166 | # 167 | 168 | MCU = cortex-m4 169 | 170 | #TRGT = arm-elf- 171 | TRGT = arm-none-eabi- 172 | CC = $(TRGT)gcc 173 | CPPC = $(TRGT)g++ 174 | # Enable loading with g++ only if you need C++ runtime support. 175 | # NOTE: You can use C++ even without C++ support if you are careful. C++ 176 | # runtime support makes code size explode. 177 | LD = $(TRGT)gcc 178 | #LD = $(TRGT)g++ 179 | CP = $(TRGT)objcopy 180 | AS = $(TRGT)gcc -x assembler-with-cpp 181 | AR = $(TRGT)ar 182 | OD = $(TRGT)objdump 183 | SZ = $(TRGT)size 184 | HEX = $(CP) -O ihex 185 | BIN = $(CP) -O binary 186 | 187 | # ARM-specific options here 188 | AOPT = 189 | 190 | # THUMB-specific options here 191 | TOPT = -mthumb -DTHUMB 192 | 193 | # Define C warning options here 194 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes 195 | 196 | # Define C++ warning options here 197 | CPPWARN = -Wall -Wextra -Wundef 198 | 199 | # 200 | # Compiler settings 201 | ############################################################################## 202 | 203 | ############################################################################## 204 | # Start of user section 205 | # 206 | 207 | # List all user C define here, like -D_DEBUG=1 208 | # CMSIS 209 | UDEFS = -DARM_MATH_CM4 -D__FPU_PRESENT -DCHPRINTF_USE_FLOAT=1 210 | 211 | # Define ASM defines here 212 | UADEFS = 213 | 214 | # List all user directories here 215 | UINCDIR = 216 | 217 | # List the user directory to look for the libraries here 218 | ULIBDIR = $(CMSIS)/Lib/GCC 219 | 220 | # List all user libraries here 221 | ULIBS = 222 | 223 | # 224 | # End of user defines 225 | ############################################################################## 226 | 227 | RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC 228 | include $(RULESPATH)/rules.mk 229 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/src/lan8720.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #include "ch.h" 27 | #include "project.h" 28 | #include "lwipthread.h" 29 | #include 30 | #include "lwip/ip_addr.h" 31 | #include "lwip/api.h" 32 | #include "lwip/err.h" 33 | 34 | #define IP(A,B,C,D) htonl(A<<24 | B<<16 | C<<8 | D) 35 | #define LAN8720_IPADDR IP(192, 168, 1, 60) 36 | #define LAN8720_GATEWAY IP(192, 168, 1, 1) 37 | #define LAN8720_NETMASK IP(255, 255, 255, 0) 38 | 39 | #define LAN8720_ETHADDR_0 0xC2 40 | #define LAN8720_ETHADDR_1 0xAF 41 | #define LAN8720_ETHADDR_2 0x51 42 | #define LAN8720_ETHADDR_3 0x03 43 | #define LAN8720_ETHADDR_4 0xCF 44 | #define LAN8720_ETHADDR_5 0x46 45 | 46 | #define LOCAL_PORT 50001 47 | 48 | void lan8720Init(void) 49 | { 50 | struct lwipthread_opts opts; 51 | uint8_t optsMAC[6] = {LAN8720_ETHADDR_0, 52 | LAN8720_ETHADDR_1, 53 | LAN8720_ETHADDR_2, 54 | LAN8720_ETHADDR_3, 55 | LAN8720_ETHADDR_4, 56 | LAN8720_ETHADDR_5}; 57 | 58 | 59 | memset(&opts, 0, sizeof(opts)); 60 | opts.macaddress = optsMAC; 61 | opts.address = LAN8720_IPADDR; 62 | opts.netmask = LAN8720_NETMASK; 63 | opts.gateway = LAN8720_GATEWAY; 64 | 65 | lwipInit(&opts); 66 | } 67 | 68 | void lan8720Shutdown(void) 69 | { 70 | 71 | 72 | } 73 | 74 | 75 | void lan8720TestUDP(void) 76 | { 77 | err_t lwipErr = ERR_OK; 78 | struct netconn *udpConn = NULL; 79 | struct netbuf *udpSendBuf = NULL; 80 | struct netbuf *udpRecvBuf = NULL; 81 | uint8_t *payload = NULL; 82 | ip_addr_t remoteIp; 83 | uint16_t remotePort = 0; 84 | uint32_t rxDataLength = 0; 85 | 86 | if (NULL == (udpConn = netconn_new(NETCONN_UDP))) 87 | { 88 | while(1); 89 | } 90 | 91 | if (ERR_OK != (lwipErr = netconn_bind(udpConn, IP_ADDR_ANY, LOCAL_PORT))) 92 | { 93 | PRINT("LWIP ERROR: %s", lwip_strerr(lwipErr)); 94 | while(1); 95 | } 96 | 97 | while(1) 98 | { 99 | if (ERR_OK != (lwipErr = netconn_recv(udpConn, &udpRecvBuf))) 100 | { 101 | if (ERR_IS_FATAL(lwipErr)) 102 | { 103 | while(1); 104 | } 105 | 106 | chThdSleep(MS2ST(2)); 107 | continue; 108 | } 109 | 110 | remoteIp = *netbuf_fromaddr(udpRecvBuf); 111 | remotePort = netbuf_fromport(udpRecvBuf); 112 | rxDataLength = netbuf_len(udpRecvBuf); 113 | 114 | udpSendBuf = netbuf_new(); 115 | 116 | if (NULL == (payload = netbuf_alloc(udpSendBuf, rxDataLength))) 117 | { 118 | while(1); 119 | } 120 | 121 | netbuf_copy(udpRecvBuf, payload, rxDataLength); 122 | 123 | if (ERR_OK != (lwipErr = netconn_sendto(udpConn, udpSendBuf, 124 | &remoteIp, remotePort))) 125 | { 126 | PRINT("LWIP ERROR: %s", lwip_strerr(lwipErr)); 127 | while(1); 128 | } 129 | 130 | netbuf_delete(udpSendBuf); 131 | netbuf_delete(udpRecvBuf); 132 | } 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/src/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "ch.h" 28 | #include "hal.h" 29 | #include "chprintf.h" 30 | #include "project.h" 31 | 32 | #define SERIAL_PRINT_DRIVER SD1 33 | 34 | static mutex_t serialPrintMtx; 35 | 36 | static THD_WORKING_AREA(waThread1, 128); 37 | 38 | static THD_FUNCTION(Thread1, arg) 39 | { 40 | (void)arg; 41 | chRegSetThreadName("blinker"); 42 | while (TRUE) 43 | { 44 | LED_GREEN_TOGGLE(); 45 | chThdSleepMilliseconds(500); 46 | } 47 | } 48 | 49 | void debugInit(void) 50 | { 51 | /* Configure Debug Serial */ 52 | sdStart(&SERIAL_PRINT_DRIVER, NULL); 53 | palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(7)); 54 | palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(7)); 55 | chMtxObjectInit(&serialPrintMtx); 56 | } 57 | 58 | void debugShutdown(void) 59 | { 60 | sdStop(&SERIAL_PRINT_DRIVER); 61 | } 62 | 63 | void debugSerialPrint(const char * fmt, ...) 64 | { 65 | va_list ap; 66 | va_start(ap, fmt); 67 | chMtxLock(&serialPrintMtx); 68 | chvprintf((BaseSequentialStream*)&SERIAL_PRINT_DRIVER, fmt, ap); 69 | chMtxUnlock(&serialPrintMtx); 70 | va_end(ap); 71 | } 72 | 73 | int main(void) 74 | { 75 | halInit(); 76 | chSysInit(); 77 | debugInit(); 78 | 79 | PRINT("Main is running",0); 80 | 81 | lan8720Init(); 82 | 83 | chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); 84 | 85 | lan8720TestUDP(); 86 | 87 | while(1) 88 | { 89 | chThdSleep(S2ST(1)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/src/project.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef _PROJECT_H_ 28 | #define _PROJECT_H_ 29 | 30 | #include "ch.h" 31 | 32 | void mp45dt02Init(void); 33 | void mp45dt02Shutdown(void); 34 | 35 | void lan8720Init(void); 36 | void lan8720Shutdown(void); 37 | void lan8720TestUDP(void); 38 | 39 | void debugSerialPrint(const char * fmt, ...); 40 | 41 | #define _PRINT(FMT, ...) 42 | 43 | #if 1 44 | #define PRINT(FMT, ...) \ 45 | debugSerialPrint("(%s:%d) " FMT "\n\r", __FILE__, __LINE__, __VA_ARGS__) 46 | #else 47 | #define PRINT(FMT, ...) _PRINT(FMT, ...) 48 | #endif 49 | 50 | #define PRINT_ERROR(FMT, ...)\ 51 | PRINT("ERROR:" FMT, __VA_ARGS__); \ 52 | \ 53 | while (1) \ 54 | { \ 55 | LED_RED_SET(); \ 56 | chThdSleepMilliseconds(500); \ 57 | LED_RED_CLEAR(); \ 58 | chThdSleepMilliseconds(500); \ 59 | LED_RED_SET(); \ 60 | chSysHalt("ERROR"); \ 61 | } 62 | 63 | #define LED_ORANGE_SET() palSetPad(GPIOD, GPIOD_LED3); 64 | #define LED_ORANGE_CLEAR() palClearPad(GPIOD, GPIOD_LED3); 65 | #define LED_ORANGE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED3); 66 | 67 | #define LED_GREEN_SET() palSetPad(GPIOD, GPIOD_LED4); 68 | #define LED_GREEN_CLEAR() palClearPad(GPIOD, GPIOD_LED4); 69 | #define LED_GREEN_TOGGLE() palTogglePad(GPIOD, GPIOD_LED4); 70 | 71 | #define LED_RED_SET() palSetPad(GPIOD, GPIOD_LED5); 72 | #define LED_RED_CLEAR() palClearPad(GPIOD, GPIOD_LED5); 73 | #define LED_RED_TOGGLE() palTogglePad(GPIOD, GPIOD_LED5); 74 | 75 | #define LED_BLUE_SET() palSetPad(GPIOD, GPIOD_LED6); 76 | #define LED_BLUE_CLEAR() palClearPad(GPIOD, GPIOD_LED6); 77 | #define LED_BLUE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED6); 78 | 79 | #endif /* _PROJECT_H_ */ 80 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/utils/gdb_openocd.cfg: -------------------------------------------------------------------------------- 1 | # Load into GDB with -x command line argument. 2 | 3 | set height 0 4 | 5 | set print elements 0 6 | set print array on 7 | set print pretty on 8 | 9 | target remote localhost:3333 10 | monitor halt 11 | monitor reset 12 | 13 | make -j3 14 | file build/test.elf 15 | load 16 | 17 | continue 18 | 19 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/utils/udp_echo_test.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import socket 29 | import time 30 | import argparse 31 | 32 | class udp_echo(object): 33 | 34 | def __init__(self, 35 | local_ip, 36 | local_port): 37 | 38 | self.local_ip = local_ip 39 | self.local_port = int(local_port) 40 | 41 | def _loop(self, sock): 42 | while (True): 43 | try: 44 | data_bytes, (remote_ip, remote_port) = sock.recvfrom(1000) 45 | sock.sendto(data_bytes, (remote_ip,remote_port)) 46 | except socket.error: 47 | time.sleep(1.0/1000) 48 | continue 49 | 50 | def start(self): 51 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 52 | sock.bind((self.local_ip, self.local_port)) 53 | print("Listening on %s:%u" % (self.local_ip, self.local_port)) 54 | sock.setblocking(0) 55 | 56 | try: 57 | self._loop(sock) 58 | except KeyboardInterrupt: 59 | sock.close() 60 | 61 | if __name__ == "__main__": 62 | 63 | parser = argparse.ArgumentParser(description= 64 | """ 65 | A Simple UDP Echo Server. 66 | This program will create a UDP socket at the specified IP and Port 67 | number. Any datagram received will be echoed back to the sender. 68 | """) 69 | parser.add_argument("--ip", "-i", 70 | nargs="?", 71 | help="Local IP Address to listen on.") 72 | parser.add_argument("--port", "-p", 73 | nargs="?", 74 | help="Local Port Number to listen on.") 75 | cli_args = parser.parse_args() 76 | 77 | test = udp_echo(cli_args.ip,cli_args.port) 78 | test.start() 79 | 80 | -------------------------------------------------------------------------------- /test/lwip_basic_udp/utils/udp_max_throughput_tester.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import socket 29 | import time 30 | import threading 31 | import os 32 | import argparse 33 | 34 | class UdpTest(object): 35 | 36 | def __init__(self, 37 | socket, 38 | remote_udp_ip, 39 | remote_udp_port, 40 | payload_length = 128, 41 | duration = 10): 42 | 43 | self.tx_messages = [] 44 | self.rx_messages = [] 45 | self.payload_length = int(payload_length) 46 | self.duration = int(duration) 47 | self.actual_duration = 0 48 | self.socket = socket 49 | self.remote = (remote_udp_ip, int(remote_udp_port)) 50 | self.socket.setblocking(0) 51 | 52 | def _loop(self): 53 | end_time = time.time() + self.duration 54 | while time.time() < end_time: 55 | # Send 56 | try: 57 | random = os.urandom(self.payload_length) 58 | self.socket.sendto(random, self.remote) 59 | self.tx_messages.append(random) 60 | except socket.error(): 61 | pass 62 | 63 | # Receive 64 | try: 65 | data_bytes, (src_ip, src_port) = sock.recvfrom(self.payload_length) 66 | self.rx_messages.append(data_bytes) 67 | except socket.error: 68 | pass 69 | 70 | # Grab anything still being sent in reply to us 71 | stop_rx_time = time.time() + 0.2 72 | while time.time() < stop_rx_time: 73 | try: 74 | data_bytes, (src_ip, src_port) = sock.recvfrom(self.payload_length) 75 | self.rx_messages.append(data_bytes) 76 | except socket.error: 77 | pass 78 | 79 | def run(self): 80 | started = time.time() 81 | self._loop() 82 | ended = time.time() 83 | self.actual_duration = ended - started 84 | 85 | def number_messages_tx(self): 86 | return len(self.tx_messages) 87 | 88 | def number_messages_rx(self): 89 | return len(self.rx_messages) 90 | 91 | def valid_messages_rx(self): 92 | return len(set(self.tx_messages) & set(self.rx_messages)) 93 | 94 | def number_messages_lost(self): 95 | return len(self.tx_messages) - self.valid_messages_rx() 96 | 97 | def valid_througput_bps(self): 98 | valid_bytes = self.valid_messages_rx() * self.payload_length 99 | valid_bits = valid_bytes * 8.0 100 | return valid_bits / self.actual_duration 101 | 102 | def valid_througput_kbps(self): 103 | return self.valid_througput_bps()/1000 104 | 105 | def valid_througput_mbps(self): 106 | return self.valid_througput_kbps()/1000 107 | 108 | 109 | 110 | ################################################################################ 111 | def print_stats(udp_class): 112 | print("############################") 113 | print("Tx Messages: " + str(udp_class.number_messages_tx())) 114 | print("Rx Messages: " + str(udp_class.number_messages_rx())) 115 | print("Rx Messages (Valid): " + str(udp_class.number_messages_rx())) 116 | print("Lost/Corrupt Messages: " + str(udp_class.number_messages_lost())) 117 | print("UDP Throughput (b/s): " + str(udp_class.valid_througput_bps())) 118 | print("UDP Throughput (mb/s): " + str(udp_class.valid_througput_mbps())) 119 | 120 | ################################################################################ 121 | 122 | 123 | if __name__ == "__main__": 124 | 125 | parser = argparse.ArgumentParser(description= 126 | """ 127 | Attempts to send as many UDP messages as possible to the remote host. 128 | UDP message payload will be of specified length, filled with random data. 129 | """) 130 | parser.add_argument("--local-ip", 131 | nargs="?", 132 | help="Local IP Address to listen on.") 133 | 134 | parser.add_argument("--local-port", 135 | nargs="?", 136 | help="Local Port Number to listen on.") 137 | 138 | parser.add_argument("--remote-ip", 139 | nargs="?", 140 | help="Remote IP Address to communicate to.") 141 | 142 | parser.add_argument("--remote-port", 143 | nargs="?", 144 | help="Remote Port Number to communicate to.") 145 | 146 | parser.add_argument("--udp-payload-length", 147 | nargs="?", 148 | help="THe number of random bytes to insert into UDP payload.") 149 | 150 | 151 | cli_args = parser.parse_args() 152 | 153 | ################################################################################ 154 | 155 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 156 | sock.bind((cli_args.local_ip, int(cli_args.local_port))) 157 | 158 | test_thd = UdpTest(socket = sock, 159 | remote_udp_ip = cli_args.remote_ip, 160 | remote_udp_port = cli_args.remote_port, 161 | payload_length = cli_args.udp_payload_length) 162 | test_thd.run() 163 | print_stats(test_thd) 164 | 165 | sock.close() 166 | 167 | ################################################################################ 168 | 169 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/README.md: -------------------------------------------------------------------------------- 1 | You can find a related write-up of PDM at: 2 | www.theunterminatedstring.com/probing-pdm/ 3 | 4 | # I2S Setup: 5 | 6 | The I2S driver is configured to sample the MP45DT02 at 1024 kHz. This 1-bit data 7 | stream is ultimately used as the input to a FIR filter with decimation factor of 8 | 64. The result of filtering is a 16 kHz PCM output stream. 9 | 10 | To achieve this the following values were used: 11 | 12 | ## I2S Settings in src/mp45dt02_pdm.c: 13 | 14 | I2SDIV = 42 15 | I2SODD = 0 16 | 17 | ## I2S Settings in src/mcuconf.h: 18 | 19 | HSE Clock = 8 MHz 20 | PLLM = 8 21 | PLLI2SN = 258 22 | PLLI2SR = 3 23 | 24 | ## STM32 pinout: 25 | 26 | MP45DT02 CLK = PB10 27 | MP45DT02 PDM = PC3 28 | 29 | # Operation Notes: 30 | 31 | 1. Configured to capture 1 ms of 1024 kHz data between I2S interrupts. 32 | The I2S buffer needs to hold a total of 2 ms worth of data due to interrupts 33 | occuring at the buffer half full point. 34 | The buffer therefore needs to hold a total of 2048 1-bit samples (spread over 35 | 128 uint16_t's). 36 | 37 | 2. When an I2S interrupt occurs, each I2S sampled bit is "expanded" - moved from 38 | existing as a bitfield in the I2S data to it's own float. This requires 1024 39 | floats to hold 1 ms of data. 40 | 41 | 3. The array of floats are filtered and decimated by a factor of 64 to produce a 42 | 1 ms sample consisting of 16 floats. 43 | 44 | 4. These are added to the output buffer which stores 1.6 s of audio (25,600 45 | floats). 46 | 47 | 5. A 1.6 second audio sample will be taken at first run, and with each 48 | subsequent press of the user button on the STM32F4DISCOVERY. 49 | 50 | 6. When run with the GDB script (see below) the audio sample will be extracted 51 | via GDB logs allowing further examination. 52 | 53 | # Utils 54 | 55 | ## utils/fir_design.py 56 | 57 | Computes CMSIS compatible FIR filter coefficients. 58 | The following configuration variables in the file are of note: 59 | 60 | * `sampling_f` - Sampling frequency 61 | * `cutoff_f` - Number of taps 62 | * `taps_n` - Cutoff frequency 63 | 64 | The output wave file can be found, relative to where the script was run: 65 | 66 | * `./output/design/plots/fir.png` - FIR response 67 | * `./output/design/files/*` - Generated C source and header file for CMSIS 68 | 69 | ## utils/generate_tone_wave_file.py 70 | 71 | Generates a simple wave audio file, with a configurable number of 72 | superimposed tones. 73 | 74 | Tones can be changed by modifying the list `freqs`. 75 | 76 | The output wave file can be found, relative to where the script was run, 77 | `./output/test/audio/tones.wave`. 78 | 79 | ## utils/gdb_openocd.cfg 80 | 81 | This script can be sourced with `arm-none-eabi-gdb -x utils/gdb_openocd.cfg`. 82 | 83 | It contains GDB commands to be used to run and extract data for testing 84 | purposes. 85 | 86 | The commands set a breakpoint in the code, which will be hit after the 87 | audio sample has been recorded. After being hit, the sample will be read from 88 | the MCU. 89 | 90 | This will be logged to a file `./gdb_output.txt`, location relative to where GDB 91 | was started. 92 | 93 | ## utils/signal_inspection_of_gdb_log.py 94 | 95 | This will process the GDB log file containing the audio samples, preforming an 96 | FFT on the signal and additionally saving the signal to a wave audio file. 97 | 98 | It requires one argument, which is the GDB log file to be parsed. 99 | 100 | The output from the script will be saved relative to where the script is run: 101 | 102 | * `./output/inspection/audio/recorded.wave` - wave PCM audio of waveform 103 | * `./output/inspection/plots/1_signal.png` - the waveform 104 | * `./output/inspection/plots/2_signal_fft.png` - FFT of waveform 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build global options 3 | # NOTE: Can be overridden externally. 4 | # 5 | 6 | # Compiler options here. 7 | ifeq ($(USE_OPT),) 8 | USE_OPT = -O1 -ggdb3 -fomit-frame-pointer -falign-functions=16 9 | endif 10 | 11 | # C specific options here (added to USE_OPT). 12 | ifeq ($(USE_COPT),) 13 | USE_COPT = 14 | endif 15 | 16 | # C++ specific options here (added to USE_OPT). 17 | ifeq ($(USE_CPPOPT),) 18 | USE_CPPOPT = -fno-rtti 19 | endif 20 | 21 | # Enable this if you want the linker to remove unused code and data 22 | ifeq ($(USE_LINK_GC),) 23 | USE_LINK_GC = yes 24 | endif 25 | 26 | # Linker extra options here. 27 | ifeq ($(USE_LDOPT),) 28 | USE_LDOPT = 29 | endif 30 | 31 | # Enable this if you want link time optimizations (LTO) 32 | ifeq ($(USE_LTO),) 33 | USE_LTO = no 34 | endif 35 | 36 | # If enabled, this option allows to compile the application in THUMB mode. 37 | ifeq ($(USE_THUMB),) 38 | USE_THUMB = yes 39 | endif 40 | 41 | # Enable this if you want to see the full log while compiling. 42 | ifeq ($(USE_VERBOSE_COMPILE),) 43 | USE_VERBOSE_COMPILE = no 44 | endif 45 | 46 | # If enabled, this option makes the build process faster by not compiling 47 | # modules not used in the current configuration. 48 | ifeq ($(USE_SMART_BUILD),) 49 | USE_SMART_BUILD = yes 50 | endif 51 | 52 | # 53 | # Build global options 54 | ############################################################################## 55 | 56 | ############################################################################## 57 | # Architecture or project specific options 58 | # 59 | 60 | # Stack size to be allocated to the Cortex-M process stack. This stack is 61 | # the stack used by the main() thread. 62 | ifeq ($(USE_PROCESS_STACKSIZE),) 63 | USE_PROCESS_STACKSIZE = 0x400 64 | endif 65 | 66 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This 67 | # stack is used for processing interrupts and exceptions. 68 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) 69 | USE_EXCEPTIONS_STACKSIZE = 0x400 70 | endif 71 | 72 | # Enables the use of FPU on Cortex-M4 (no, softfp, hard). 73 | ifeq ($(USE_FPU),) 74 | USE_FPU = hard 75 | endif 76 | 77 | # 78 | # Architecture or project specific options 79 | ############################################################################## 80 | 81 | ############################################################################## 82 | # Project, sources and paths 83 | # 84 | 85 | # Define project name here 86 | PROJECT = test 87 | 88 | # Imported source files and paths 89 | CHIBIOS = ../../../lib/ChibiOS 90 | CMSIS= ../../../lib/CMSIS/CMSIS 91 | BOARD= ../../../board_stm32f4_dis_bb 92 | 93 | # Startup files. 94 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk 95 | # HAL-OSAL files (optional). 96 | include $(CHIBIOS)/os/hal/hal.mk 97 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk 98 | include $(CHIBIOS)/os/hal/osal/rt/osal.mk 99 | # RTOS files (optional). 100 | include $(CHIBIOS)/os/rt/rt.mk 101 | include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk 102 | # Other files (optional). 103 | include $(BOARD)/board.mk 104 | 105 | # Define linker script file here 106 | LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld 107 | 108 | # C sources that can be compiled in ARM or THUMB mode depending on the global 109 | # setting. 110 | CSRC = $(STARTUPSRC) \ 111 | $(KERNSRC) \ 112 | $(PORTSRC) \ 113 | $(OSALSRC) \ 114 | $(HALSRC) \ 115 | $(PLATFORMSRC) \ 116 | $(BOARDSRC) \ 117 | $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ 118 | $(CHIBIOS)/os/various/evtimer.c \ 119 | $(LWSRC) \ 120 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c \ 121 | $(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c \ 122 | mp45dt02_pdm.c \ 123 | autogen_fir_coeffs.c \ 124 | main.c \ 125 | debug.c 126 | 127 | 128 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global 129 | # setting. 130 | CPPSRC = 131 | 132 | # C sources to be compiled in ARM mode regardless of the global setting. 133 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 134 | # option that results in lower performance and larger code size. 135 | ACSRC = 136 | 137 | # C++ sources to be compiled in ARM mode regardless of the global setting. 138 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 139 | # option that results in lower performance and larger code size. 140 | ACPPSRC = 141 | 142 | # C sources to be compiled in THUMB mode regardless of the global setting. 143 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 144 | # option that results in lower performance and larger code size. 145 | TCSRC = 146 | 147 | # C sources to be compiled in THUMB mode regardless of the global setting. 148 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 149 | # option that results in lower performance and larger code size. 150 | TCPPSRC = 151 | 152 | # List ASM source files here 153 | ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) 154 | 155 | INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ 156 | $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ 157 | $(CHIBIOS)/os/hal/lib/streams \ 158 | $(CHIBIOS)/os/various \ 159 | $(LWINC) \ 160 | $(CMSIS)/Include 161 | 162 | # 163 | # Project, sources and paths 164 | ############################################################################## 165 | 166 | ############################################################################## 167 | # Compiler settings 168 | # 169 | 170 | MCU = cortex-m4 171 | 172 | #TRGT = arm-elf- 173 | TRGT = arm-none-eabi- 174 | CC = $(TRGT)gcc 175 | CPPC = $(TRGT)g++ 176 | # Enable loading with g++ only if you need C++ runtime support. 177 | # NOTE: You can use C++ even without C++ support if you are careful. C++ 178 | # runtime support makes code size explode. 179 | LD = $(TRGT)gcc 180 | #LD = $(TRGT)g++ 181 | CP = $(TRGT)objcopy 182 | AS = $(TRGT)gcc -x assembler-with-cpp 183 | AR = $(TRGT)ar 184 | OD = $(TRGT)objdump 185 | SZ = $(TRGT)size 186 | HEX = $(CP) -O ihex 187 | BIN = $(CP) -O binary 188 | 189 | # ARM-specific options here 190 | AOPT = 191 | 192 | # THUMB-specific options here 193 | TOPT = -mthumb -DTHUMB 194 | 195 | # Define C warning options here 196 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes 197 | 198 | # Define C++ warning options here 199 | CPPWARN = -Wall -Wextra -Wundef 200 | 201 | # 202 | # Compiler settings 203 | ############################################################################## 204 | 205 | ############################################################################## 206 | # Start of user section 207 | # 208 | 209 | # List all user C define here, like -D_DEBUG=1 210 | # CMSIS 211 | UDEFS = -DARM_MATH_CM4 -D__FPU_PRESENT -DCHPRINTF_USE_FLOAT=1 212 | 213 | # Define ASM defines here 214 | UADEFS = 215 | 216 | # List all user directories here 217 | UINCDIR = 218 | 219 | # List the user directory to look for the libraries here 220 | ULIBDIR = 221 | 222 | # List all user libraries here 223 | ULIBS = 224 | 225 | # 226 | # End of user defines 227 | ############################################################################## 228 | 229 | RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC 230 | include $(RULESPATH)/rules.mk 231 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/autogen_fir_coeffs.h: -------------------------------------------------------------------------------- 1 | /* 2 | This is an auto-generated file. 3 | 4 | Generated on: 2016-03-29 21:10 5 | 6 | Design Parameters: 7 | Sampling Frequency: 1024000.0 Hz 8 | Cutoff Frequency: 6000.0 Hz 9 | Taps: 256 10 | */ 11 | 12 | #ifndef __AUTOGEN_FIR_COEFFS__ 13 | #define __AUTOGEN_FIR_COEFFS__ 14 | 15 | #include "arm_math.h" 16 | 17 | #define FIR_COEFFS_LEN 256 18 | extern float32_t firCoeffs[FIR_COEFFS_LEN]; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/debug.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #include "debug.h" 27 | #include "chprintf.h" 28 | 29 | #define SERIAL_PRINT_DRIVER SD1 30 | 31 | static mutex_t serialPrintMtx; 32 | 33 | void debugInit(void) 34 | { 35 | /* Configure Debug Serial */ 36 | sdStart(&SERIAL_PRINT_DRIVER, NULL); 37 | palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(7)); 38 | palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(7)); 39 | chMtxObjectInit(&serialPrintMtx); 40 | } 41 | 42 | void debugShutdown(void) 43 | { 44 | sdStop(&SERIAL_PRINT_DRIVER); 45 | } 46 | 47 | void debugSerialPrint(const char * fmt, ...) 48 | { 49 | va_list ap; 50 | va_start(ap, fmt); 51 | chMtxLock(&serialPrintMtx); 52 | chvprintf((BaseSequentialStream*)&SERIAL_PRINT_DRIVER, fmt, ap); 53 | chMtxUnlock(&serialPrintMtx); 54 | va_end(ap); 55 | } 56 | 57 | void HardFault_Handler(void) 58 | { 59 | LED_RED_SET(); 60 | while (true); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/debug.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef _DEBUG_h_ 28 | #define _DEBUG_h_ 29 | 30 | #include "ch.h" 31 | #include "hal.h" 32 | 33 | void debugInit(void); 34 | void debugShutdown(void); 35 | void debugSerialPrint(const char * fmt, ...); 36 | 37 | #if 1 38 | #define PRINT(FMT, ...) \ 39 | debugSerialPrint("(%s:%d) " FMT "\n\r", __FILE__, __LINE__, __VA_ARGS__) 40 | #else 41 | #define PRINT(FMT, ...) 42 | #endif 43 | 44 | #define PRINT_ERROR(FMT, ...)\ 45 | PRINT("ERROR:" FMT, __VA_ARGS__); \ 46 | \ 47 | while (1) \ 48 | { \ 49 | LED_RED_SET(); \ 50 | chThdSleepMilliseconds(500); \ 51 | LED_RED_CLEAR(); \ 52 | chThdSleepMilliseconds(500); \ 53 | LED_RED_SET(); \ 54 | chSysHalt("ERROR"); \ 55 | } 56 | 57 | #define LED_ORANGE_SET() palSetPad(GPIOD, GPIOD_LED3); 58 | #define LED_ORANGE_CLEAR() palClearPad(GPIOD, GPIOD_LED3); 59 | #define LED_ORANGE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED3); 60 | 61 | #define LED_GREEN_SET() palSetPad(GPIOD, GPIOD_LED4); 62 | #define LED_GREEN_CLEAR() palClearPad(GPIOD, GPIOD_LED4); 63 | #define LED_GREEN_TOGGLE() palTogglePad(GPIOD, GPIOD_LED4); 64 | 65 | #define LED_RED_SET() palSetPad(GPIOD, GPIOD_LED5); 66 | #define LED_RED_CLEAR() palClearPad(GPIOD, GPIOD_LED5); 67 | #define LED_RED_TOGGLE() palTogglePad(GPIOD, GPIOD_LED5); 68 | 69 | #define LED_BLUE_SET() palSetPad(GPIOD, GPIOD_LED6); 70 | #define LED_BLUE_CLEAR() palClearPad(GPIOD, GPIOD_LED6); 71 | #define LED_BLUE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED6); 72 | 73 | #endif /* Header Guard*/ 74 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "ch.h" 28 | #include "hal.h" 29 | #include "mp45dt02_pdm.h" 30 | #include "debug.h" 31 | 32 | 33 | static THD_WORKING_AREA(waThread1, 128); 34 | static THD_FUNCTION(Thread1, arg) 35 | { 36 | (void)arg; 37 | chRegSetThreadName("blinker"); 38 | while (TRUE) 39 | { 40 | LED_GREEN_TOGGLE(); 41 | chThdSleepMilliseconds(500); 42 | } 43 | } 44 | 45 | 46 | int main(void) 47 | { 48 | halInit(); 49 | chSysInit(); 50 | debugInit(); 51 | 52 | PRINT("Main is running",0); 53 | 54 | chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); 55 | 56 | mp45dt02Init(); 57 | 58 | while(1) 59 | { 60 | chThdSleep(S2ST(1)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/src/mp45dt02_pdm.h: -------------------------------------------------------------------------------- 1 | #ifndef _MP45DT02_PDM_H_ 2 | #define _MP45DT02_PDM_H_ 3 | 4 | void mp45dt02Init(void); 5 | void mp45dt02Shutdown(void); 6 | 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/utils/fir_design.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python2 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import numpy as np 29 | import os 30 | from scipy import signal as signal 31 | from scipy.fftpack import fft 32 | import matplotlib.pyplot as plot 33 | import time 34 | 35 | ################################################################################ 36 | ##### Configuration ##### 37 | ################################################################################ 38 | 39 | dir_text = "./output/design/files/" 40 | dir_plots = "./output/design/plots/" 41 | 42 | file_c_coeff = "autogen_fir_coeffs" 43 | 44 | # Sampling frequency, Hz 45 | sampling_f = 1.024 * 10**6 46 | # Cutoff frequency, Hz 47 | cutoff_f = 6000.0 48 | # Number of taps/ coefficients for FIR filter. (Order + 1) 49 | taps_n = 256 50 | # Number of samples to be processed at once (used for generated C file.) 51 | 52 | ################################################################################ 53 | ##### Setup ##### 54 | ################################################################################ 55 | 56 | nyquist_f = sampling_f / 2.0 57 | 58 | if dir_plots and not os.path.exists(dir_plots): 59 | os.makedirs(dir_plots) 60 | 61 | header_string = "/*\n" 62 | header_string += "This is an auto-generated file.\n\n" 63 | header_string += "Generated on: %s\n\n" %(time.strftime("%Y-%m-%d %H:%M")) 64 | header_string += "Design Parameters:\n" 65 | header_string += " Sampling Frequency: %s Hz\n" %(str(sampling_f)) 66 | header_string += " Cutoff Frequency: %s Hz\n" %(str(cutoff_f)) 67 | header_string += " Taps: %s\n" %(str(taps_n)) 68 | header_string += "*/\n\n" 69 | ################################################################################ 70 | ##### Create FIR ##### 71 | ################################################################################ 72 | 73 | fir_coeff = signal.firwin(taps_n, cutoff=cutoff_f, nyq = nyquist_f) 74 | 75 | w, h = signal.freqz(fir_coeff) 76 | 77 | unnormalised_f = w * nyquist_f/np.pi 78 | unnormalised_f = unnormalised_f[0:20] 79 | 80 | fig, ax1 = plot.subplots() 81 | plot.title('FIR Response') 82 | 83 | ax1.plot(unnormalised_f, 20 * np.log10(abs(h))[0:20], 'b') 84 | ax1.set_ylabel('Amplitude [dB]', color='b') 85 | for tl in ax1.get_yticklabels(): 86 | tl.set_color('b') 87 | 88 | ax2 = ax1.twinx() 89 | ax2.plot(unnormalised_f, np.unwrap(np.angle(h))[0:20], 'g') 90 | ax2.set_ylabel('Angle [radians]', color='g') 91 | for tl in ax2.get_yticklabels(): 92 | tl.set_color('g') 93 | 94 | ax1.set_xlabel('Frequency [Hz]') 95 | 96 | plot.grid() 97 | plot.axis('tight') 98 | plot.savefig(dir_plots + "fir.png") 99 | plot.close() 100 | 101 | ################################################################################ 102 | ##### Create FIR C Files ##### 103 | ################################################################################ 104 | 105 | fir_coeff_reversed = fir_coeff[::-1] 106 | 107 | if not os.path.exists(dir_text): 108 | os.makedirs(dir_text) 109 | 110 | # Header File 111 | h_file_handle = open(dir_text + file_c_coeff + ".h","w") 112 | 113 | h_file_handle.write(header_string) 114 | h_file_handle.write("#ifndef __%s__\n" %file_c_coeff.upper()) 115 | h_file_handle.write("#define __%s__\n\n" %file_c_coeff.upper()) 116 | 117 | h_file_handle.write("#include \"arm_math.h\"\n\n") 118 | 119 | h_file_handle.write("#define FIR_COEFFS_LEN %s\n" %taps_n) 120 | 121 | h_file_handle.write("extern float32_t firCoeffs[FIR_COEFFS_LEN];\n") 122 | 123 | h_file_handle.write("\n#endif\n") 124 | h_file_handle.close() 125 | 126 | # C File 127 | file_handle = open(dir_text + file_c_coeff + ".c","w") 128 | file_handle.write(header_string) 129 | 130 | file_handle.write("#include \"" + file_c_coeff + ".h\"\n\n") 131 | 132 | # Float Coeffs 133 | file_handle.write("float32_t firCoeffs[FIR_COEFFS_LEN] = {\n") 134 | for f in fir_coeff_reversed: 135 | file_handle.write(" %.23f,\n" %f) 136 | file_handle.write("};\n\n") 137 | 138 | file_handle.close() 139 | 140 | 141 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/utils/gdb_openocd.cfg: -------------------------------------------------------------------------------- 1 | # Load into GDG with -x command line argument. 2 | 3 | set print pretty on 4 | target remote localhost:3333 5 | monitor halt 6 | monitor reset 7 | file src/build/test.elf 8 | load 9 | 10 | set height 0 11 | set print elements 0 12 | set print array on 13 | set logging file gdb_output.txt 14 | set logging overwrite on 15 | 16 | break mp45dt02_pdm.c:240 17 | command 18 | set logging on 19 | print output 20 | set logging off 21 | continue 22 | end 23 | 24 | continue 25 | 26 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/utils/generate_tone_wav_file.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python2 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import numpy as np 29 | import wave 30 | import os 31 | import struct 32 | import operator 33 | 34 | ################################################################################ 35 | # Docs 36 | # Creates a wave file of specified sinusoidal waves. 37 | ################################################################################ 38 | 39 | ################################################################################ 40 | # Configuration 41 | ################################################################################ 42 | # The list of frequencies to be superimposed in the output wave form 43 | freqs = [500, 2000, 4000, 7000, 10000, 11000] 44 | # Output Directory 45 | dir_files = "./output/test/audio/" 46 | # Sampling frequency of output wave file 47 | sampling_freq = 32000 48 | # Playback duration of output wave file 49 | sampling_duration = 10 50 | # Output file name 51 | wav_file = dir_files + "tones.wave" 52 | 53 | ################################################################################ 54 | 55 | if not os.path.exists(dir_files): 56 | os.makedirs(dir_files) 57 | 58 | sampling_number = sampling_duration * sampling_freq 59 | 60 | ################################################################################ 61 | t = np.arange(sampling_number) / float(sampling_freq) 62 | 63 | signal = [0] * sampling_number 64 | 65 | for freq in freqs: 66 | tone = np.cos(t*2*np.pi*freq) 67 | signal = map(operator.add, signal, tone) 68 | 69 | wav = wave.open(wav_file, "w") 70 | wav.setparams((1, # nchannels 71 | 2, # sampwidth 72 | sampling_freq, # framerate 73 | 0, # nframes 74 | "NONE", # comptype 75 | "not compressed" # compname 76 | )) 77 | 78 | scaling = 32760 / np.max(signal) 79 | packed = [] 80 | for sample in signal: 81 | sample = sample * scaling 82 | packed.append(struct.pack("h", int(sample))) 83 | 84 | wav.writeframes("".join(packed)) 85 | wav.close() 86 | 87 | print "Generated %s" %wav_file 88 | 89 | 90 | -------------------------------------------------------------------------------- /test/mp45dt02_basic_cmsis_filtering/utils/signal_inspection_of_gdb_log.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python2 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | 29 | ################################################################################ 30 | # Usage 31 | ################################################################################ 32 | 33 | import numpy as np 34 | import matplotlib.pyplot as plot 35 | from scipy.fftpack import fft 36 | import sys 37 | import re 38 | import os 39 | import wave 40 | import struct 41 | 42 | ################################################################################ 43 | # Configuration 44 | ################################################################################ 45 | 46 | dir_plots = "./output/inspection/plots/" 47 | dir_files = "./output/inspection/audio/" 48 | show_plots = True 49 | 50 | file_gdb = sys.argv[1] 51 | sampling_f = 16000 52 | ################################################################################ 53 | # Helper Functions 54 | ################################################################################ 55 | def show_plot(plot): 56 | if show_plots: 57 | plot.show() 58 | 59 | def get_gdb_array(arr, data): 60 | arr = arr + "\s+=\s+{(.*?)}" 61 | strs = re.compile(arr, re.DOTALL).search(data).group(1).replace(" ","").replace("\n","").split(",") 62 | return map(float, strs) 63 | 64 | def get_arm_signal(gdb_file): 65 | with open(gdb_file, "r") as f: 66 | data = f.read() 67 | 68 | signal = get_gdb_array("buffer", data) 69 | 70 | return signal 71 | 72 | ################################################################################ 73 | # Run 74 | ################################################################################ 75 | gdb_signal = sys.argv[1] 76 | 77 | if not os.path.exists(dir_plots): 78 | os.makedirs(dir_plots) 79 | 80 | if not os.path.exists(dir_files): 81 | os.makedirs(dir_files) 82 | 83 | ################################################################################ 84 | # Signal 85 | ################################################################################ 86 | signal = get_arm_signal(file_gdb) 87 | 88 | plot.figure() 89 | plot.plot(signal) 90 | plot.grid() 91 | plot.title("Filtered Signal") 92 | plot.xlabel("Sample Number") 93 | plot.ylabel("Amplitude") 94 | plot.savefig(dir_plots + "1_signal.png") 95 | 96 | show_plot(plot) 97 | plot.close() 98 | 99 | 100 | ################################################################################ 101 | # FFT Of Signal 102 | ################################################################################ 103 | 104 | fft_signal = fft(signal, sampling_f) 105 | fft_signal = fft_signal[0:len(fft_signal)/2] 106 | 107 | x = np.arange(0, (sampling_f/2), (sampling_f/2)/len(fft_signal)) 108 | 109 | start_freq = 100 110 | 111 | plot.figure() 112 | plot.plot(x[start_freq:], np.abs(fft_signal[start_freq:])) 113 | plot.grid() 114 | plot.title("FFT of Filtered Signal") 115 | plot.xlabel("Frequency [Hz]") 116 | plot.ylabel("Power") 117 | plot.savefig(dir_plots + "2_signal_fft.png") 118 | 119 | show_plot(plot) 120 | plot.close() 121 | 122 | 123 | ################################################################################ 124 | # Create WAV File 125 | ################################################################################ 126 | wav_file = dir_files + "recorded.wave" 127 | wav = wave.open(wav_file, "w") 128 | wav.setparams((1, # nchannels 129 | 2, # sampwidth 130 | sampling_f, # framerate 131 | 0, # nframes 132 | "NONE", # comptype 133 | "not compressed" # compname 134 | )) 135 | 136 | packed = [] 137 | for sample in signal: 138 | # Should this be possible? 139 | if sample > 32767: 140 | sample = 32767 141 | 142 | if sample < -32768: 143 | sample = -32768 144 | packed.append(struct.pack("h", int(sample))) 145 | 146 | wav.writeframes("".join(packed)) 147 | wav.close() 148 | 149 | wav = wave.open(wav_file, "r") 150 | print wav.getparams() 151 | wav.close() 152 | 153 | 154 | -------------------------------------------------------------------------------- /test/true_random_number_generator/README.md: -------------------------------------------------------------------------------- 1 | # STM32F4 Random Number Test 2 | 3 | Streams numbers from the STM32F407's True Random Number Generator over UDP. 4 | 5 | IP configuration of the STM32F4 and the remote target is found in `./src/project.h`. 6 | 7 | The `./utils/random_receiver.py` file can be used to capture the stream and 8 | provide the data to a 3rd party test program, such as: 9 | 10 | * [Dieharder](https://www.phy.duke.edu/~rgb/General/dieharder.php) 11 | * [PractRand](http://pracrand.sourceforge.net/) 12 | * [NIST Statistical Test Suite](http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html) 13 | 14 | 15 | # Hardware Used: 16 | 17 | * STM32F407G-DISC1 - STM32F407 Discovery Board 18 | * STM32F4DIS-EXT - STM32F4 Discovery Base Board (Used for Ethernet Phy) 19 | 20 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Build global options 3 | # NOTE: Can be overridden externally. 4 | # 5 | 6 | # Compiler options here. 7 | ifeq ($(USE_OPT),) 8 | USE_OPT = -O2 -ggdb3 -fomit-frame-pointer -falign-functions=16 9 | endif 10 | 11 | # C specific options here (added to USE_OPT). 12 | ifeq ($(USE_COPT),) 13 | USE_COPT = 14 | endif 15 | 16 | # C++ specific options here (added to USE_OPT). 17 | ifeq ($(USE_CPPOPT),) 18 | USE_CPPOPT = -fno-rtti 19 | endif 20 | 21 | # Enable this if you want the linker to remove unused code and data 22 | ifeq ($(USE_LINK_GC),) 23 | USE_LINK_GC = yes 24 | endif 25 | 26 | # Linker extra options here. 27 | ifeq ($(USE_LDOPT),) 28 | USE_LDOPT = 29 | endif 30 | 31 | # Enable this if you want link time optimizations (LTO) 32 | ifeq ($(USE_LTO),) 33 | USE_LTO = no 34 | endif 35 | 36 | # If enabled, this option allows to compile the application in THUMB mode. 37 | ifeq ($(USE_THUMB),) 38 | USE_THUMB = yes 39 | endif 40 | 41 | # Enable this if you want to see the full log while compiling. 42 | ifeq ($(USE_VERBOSE_COMPILE),) 43 | USE_VERBOSE_COMPILE = no 44 | endif 45 | 46 | # If enabled, this option makes the build process faster by not compiling 47 | # modules not used in the current configuration. 48 | ifeq ($(USE_SMART_BUILD),) 49 | USE_SMART_BUILD = yes 50 | endif 51 | 52 | # 53 | # Build global options 54 | ############################################################################## 55 | 56 | ############################################################################## 57 | # Architecture or project specific options 58 | # 59 | 60 | # Stack size to be allocated to the Cortex-M process stack. This stack is 61 | # the stack used by the main() thread. 62 | ifeq ($(USE_PROCESS_STACKSIZE),) 63 | USE_PROCESS_STACKSIZE = 0x400 64 | endif 65 | 66 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This 67 | # stack is used for processing interrupts and exceptions. 68 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) 69 | USE_EXCEPTIONS_STACKSIZE = 0x400 70 | endif 71 | 72 | # Enables the use of FPU on Cortex-M4 (no, softfp, hard). 73 | ifeq ($(USE_FPU),) 74 | USE_FPU = hard 75 | endif 76 | 77 | # 78 | # Architecture or project specific options 79 | ############################################################################## 80 | 81 | ############################################################################## 82 | # Project, sources and paths 83 | # 84 | 85 | # Define project name here 86 | PROJECT = test 87 | 88 | # Imported source files and paths 89 | CHIBIOS = ../../../lib/ChibiOS 90 | CMSIS= ../../../lib/CMSIS/CMSIS 91 | BOARD= ../../../board_stm32f4_dis_bb 92 | 93 | # Startup files. 94 | include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk 95 | # HAL-OSAL files (optional). 96 | include $(CHIBIOS)/os/hal/hal.mk 97 | include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk 98 | include $(CHIBIOS)/os/hal/osal/rt/osal.mk 99 | # RTOS files (optional). 100 | include $(CHIBIOS)/os/rt/rt.mk 101 | include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk 102 | # Other files (optional). 103 | include $(CHIBIOS)/os/various/lwip_bindings/lwip.mk 104 | include $(BOARD)/board.mk 105 | 106 | # Define linker script file here 107 | LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld 108 | 109 | # C sources that can be compiled in ARM or THUMB mode depending on the global 110 | # setting. 111 | CSRC = $(STARTUPSRC) \ 112 | $(KERNSRC) \ 113 | $(PORTSRC) \ 114 | $(OSALSRC) \ 115 | $(HALSRC) \ 116 | $(PLATFORMSRC) \ 117 | $(BOARDSRC) \ 118 | $(TESTSRC) \ 119 | $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ 120 | $(CHIBIOS)/os/various/evtimer.c \ 121 | $(LWSRC) \ 122 | main.c \ 123 | ip_random_tx.c \ 124 | random.c 125 | 126 | 127 | # C++ sources that can be compiled in ARM or THUMB mode depending on the global 128 | # setting. 129 | CPPSRC = 130 | 131 | # C sources to be compiled in ARM mode regardless of the global setting. 132 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 133 | # option that results in lower performance and larger code size. 134 | ACSRC = 135 | 136 | # C++ sources to be compiled in ARM mode regardless of the global setting. 137 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 138 | # option that results in lower performance and larger code size. 139 | ACPPSRC = 140 | 141 | # C sources to be compiled in THUMB mode regardless of the global setting. 142 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 143 | # option that results in lower performance and larger code size. 144 | TCSRC = 145 | 146 | # C sources to be compiled in THUMB mode regardless of the global setting. 147 | # NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler 148 | # option that results in lower performance and larger code size. 149 | TCPPSRC = 150 | 151 | # List ASM source files here 152 | ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) 153 | 154 | INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ 155 | $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ 156 | $(CHIBIOS)/os/hal/lib/streams \ 157 | $(CHIBIOS)/os/various \ 158 | $(LWINC) \ 159 | $(CMSIS)/Include 160 | 161 | # 162 | # Project, sources and paths 163 | ############################################################################## 164 | 165 | ############################################################################## 166 | # Compiler settings 167 | # 168 | 169 | MCU = cortex-m4 170 | 171 | #TRGT = arm-elf- 172 | TRGT = arm-none-eabi- 173 | CC = $(TRGT)gcc 174 | CPPC = $(TRGT)g++ 175 | # Enable loading with g++ only if you need C++ runtime support. 176 | # NOTE: You can use C++ even without C++ support if you are careful. C++ 177 | # runtime support makes code size explode. 178 | LD = $(TRGT)gcc 179 | #LD = $(TRGT)g++ 180 | CP = $(TRGT)objcopy 181 | AS = $(TRGT)gcc -x assembler-with-cpp 182 | AR = $(TRGT)ar 183 | OD = $(TRGT)objdump 184 | SZ = $(TRGT)size 185 | HEX = $(CP) -O ihex 186 | BIN = $(CP) -O binary 187 | 188 | # ARM-specific options here 189 | AOPT = 190 | 191 | # THUMB-specific options here 192 | TOPT = -mthumb -DTHUMB 193 | 194 | # Define C warning options here 195 | CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes 196 | 197 | # Define C++ warning options here 198 | CPPWARN = -Wall -Wextra -Wundef 199 | 200 | # 201 | # Compiler settings 202 | ############################################################################## 203 | 204 | ############################################################################## 205 | # Start of user section 206 | # 207 | 208 | # List all user C define here, like -D_DEBUG=1 209 | # CMSIS 210 | UDEFS = -DARM_MATH_CM4 -D__FPU_PRESENT -DCHPRINTF_USE_FLOAT=1 211 | 212 | # Define ASM defines here 213 | UADEFS = 214 | 215 | # List all user directories here 216 | UINCDIR = 217 | 218 | # List the user directory to look for the libraries here 219 | ULIBDIR = $(CMSIS)/Lib/GCC 220 | 221 | # List all user libraries here 222 | ULIBS = 223 | 224 | # 225 | # End of user defines 226 | ############################################################################## 227 | 228 | RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC 229 | include $(RULESPATH)/rules.mk 230 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/ip_random_tx.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #include 27 | #include 28 | #include "ch.h" 29 | #include "project.h" 30 | #include "lwipthread.h" 31 | #include "lwip/ip_addr.h" 32 | #include "lwip/api.h" 33 | #include "lwip/err.h" 34 | #include "random.h" 35 | 36 | #define PAYLOAD_SAMPLES 365 37 | 38 | void ipInit(void) 39 | { 40 | struct lwipthread_opts opts; 41 | uint8_t optsMAC[6] = {STM32_ETHADDR_0, 42 | STM32_ETHADDR_1, 43 | STM32_ETHADDR_2, 44 | STM32_ETHADDR_3, 45 | STM32_ETHADDR_4, 46 | STM32_ETHADDR_5}; 47 | 48 | 49 | memset(&opts, 0, sizeof(opts)); 50 | opts.macaddress = optsMAC; 51 | opts.address = STM32_IPADDR; 52 | opts.netmask = STM32_NETMASK; 53 | opts.gateway = STM32_GATEWAY; 54 | 55 | lwipInit(&opts); 56 | } 57 | 58 | void ipTransmitRandomLoop(void) 59 | { 60 | err_t lwipErr = ERR_OK; 61 | struct netconn *udpConn = NULL; 62 | struct netbuf *udpSendBuf = NULL; 63 | uint8_t *payload = NULL; 64 | ip_addr_t remoteIp; 65 | uint16_t remotePort; 66 | 67 | uint32_t index = 0; 68 | uint32_t random = 0; 69 | 70 | remoteIp.addr = REMOTE_IP; 71 | remotePort = REMOTE_PORT; 72 | 73 | chThdSetPriority(LOWPRIO); 74 | 75 | if (NULL == (udpConn = netconn_new(NETCONN_UDP))) 76 | { 77 | PRINT_ERROR("New netconn failed",0); 78 | } 79 | 80 | if (ERR_OK != (lwipErr = netconn_bind(udpConn, IP_ADDR_ANY, STM32_PORT))) 81 | { 82 | PRINT_ERROR("LWIP ERROR: %s", lwip_strerr(lwipErr)); 83 | } 84 | 85 | while(1) 86 | { 87 | if (NULL == (udpSendBuf = netbuf_new())) 88 | { 89 | PRINT_ERROR("Failed to get netbuf.", 0); 90 | while(1); 91 | } 92 | 93 | if (NULL == (payload = netbuf_alloc(udpSendBuf, 94 | PAYLOAD_SAMPLES * sizeof(uint32_t)))) 95 | { 96 | PRINT_ERROR("Failed to allocate netbuf.", 0); 97 | while(1); 98 | } 99 | 100 | for (index = 0; index < PAYLOAD_SAMPLES; index++) 101 | { 102 | if (0 != randomGet(&random)) 103 | { 104 | PRINT_ERROR("Failed to get random number.", 0); 105 | } 106 | 107 | memcpy(payload, &random, sizeof(random)); 108 | payload += sizeof(random); 109 | } 110 | 111 | if (ERR_OK != (lwipErr = netconn_sendto(udpConn, udpSendBuf, 112 | &remoteIp, remotePort))) 113 | { 114 | PRINT_ERROR("LWIP ERROR: %s", lwip_strerr(lwipErr)); 115 | } 116 | 117 | netbuf_delete(udpSendBuf); 118 | 119 | chThdYield(); 120 | } 121 | } 122 | 123 | 124 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "ch.h" 28 | #include "hal.h" 29 | #include "chprintf.h" 30 | #include "project.h" 31 | #include "random.h" 32 | 33 | static mutex_t serialPrintMtx; 34 | 35 | static THD_WORKING_AREA(blinkerThdWa, 128); 36 | static THD_FUNCTION(blinkerThd, arg) 37 | { 38 | (void)arg; 39 | chRegSetThreadName("blinker"); 40 | while (TRUE) 41 | { 42 | LED_GREEN_TOGGLE(); 43 | chThdSleepMilliseconds(500); 44 | } 45 | } 46 | 47 | void debugInit(void) 48 | { 49 | chThdCreateStatic(blinkerThdWa, 50 | sizeof(blinkerThdWa), 51 | NORMALPRIO, 52 | blinkerThd, 53 | NULL); 54 | 55 | /* Configure Debug Serial */ 56 | sdStart(&SERIAL_PRINT_DRIVER, NULL); 57 | palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(7)); 58 | palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(7)); 59 | chMtxObjectInit(&serialPrintMtx); 60 | PRINT("Debug Initialised",0); 61 | } 62 | 63 | void debugShutdown(void) 64 | { 65 | sdStop(&SERIAL_PRINT_DRIVER); 66 | } 67 | 68 | void debugSerialPrint(const char * fmt, ...) 69 | { 70 | va_list ap; 71 | va_start(ap, fmt); 72 | chMtxLock(&serialPrintMtx); 73 | chvprintf((BaseSequentialStream*)&SERIAL_PRINT_DRIVER, fmt, ap); 74 | chMtxUnlock(&serialPrintMtx); 75 | va_end(ap); 76 | } 77 | 78 | int main(void) 79 | { 80 | halInit(); 81 | chSysInit(); 82 | debugInit(); 83 | ipInit(); 84 | randomInit(); 85 | ipTransmitRandomLoop(); 86 | 87 | while(1) 88 | { 89 | chThdSleep(S2ST(1)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/project.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #ifndef _PROJECT_H_ 28 | #define _PROJECT_H_ 29 | 30 | #include "ch.h" 31 | 32 | /******************************************************************************/ 33 | /* Debug */ 34 | /******************************************************************************/ 35 | 36 | #define SERIAL_PRINT_DRIVER SD1 37 | 38 | #if 1 39 | #define PRINT(FMT, ...) \ 40 | debugSerialPrint("(%s:%d) " FMT "\n\r", __FILE__, __LINE__, __VA_ARGS__) 41 | #else 42 | #define PRINT(FMT, ...) 43 | #endif 44 | 45 | #define PRINT_ERROR(FMT, ...)\ 46 | PRINT("ERROR: " FMT, __VA_ARGS__); \ 47 | \ 48 | while (1) \ 49 | { \ 50 | LED_RED_SET(); \ 51 | chThdSleepMilliseconds(500); \ 52 | LED_RED_CLEAR(); \ 53 | chThdSleepMilliseconds(500); \ 54 | LED_RED_SET(); \ 55 | chSysHalt("ERROR"); \ 56 | } 57 | 58 | #define LED_ORANGE_SET() palSetPad(GPIOD, GPIOD_LED3); 59 | #define LED_ORANGE_CLEAR() palClearPad(GPIOD, GPIOD_LED3); 60 | #define LED_ORANGE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED3); 61 | 62 | #define LED_GREEN_SET() palSetPad(GPIOD, GPIOD_LED4); 63 | #define LED_GREEN_CLEAR() palClearPad(GPIOD, GPIOD_LED4); 64 | #define LED_GREEN_TOGGLE() palTogglePad(GPIOD, GPIOD_LED4); 65 | 66 | #define LED_RED_SET() palSetPad(GPIOD, GPIOD_LED5); 67 | #define LED_RED_CLEAR() palClearPad(GPIOD, GPIOD_LED5); 68 | #define LED_RED_TOGGLE() palTogglePad(GPIOD, GPIOD_LED5); 69 | 70 | #define LED_BLUE_SET() palSetPad(GPIOD, GPIOD_LED6); 71 | #define LED_BLUE_CLEAR() palClearPad(GPIOD, GPIOD_LED6); 72 | #define LED_BLUE_TOGGLE() palTogglePad(GPIOD, GPIOD_LED6); 73 | 74 | /******************************************************************************/ 75 | /* MAC Configuration */ 76 | /******************************************************************************/ 77 | #define STM32_ETHADDR_0 0xC2 78 | #define STM32_ETHADDR_1 0xAF 79 | #define STM32_ETHADDR_2 0x51 80 | #define STM32_ETHADDR_3 0x03 81 | #define STM32_ETHADDR_4 0xCF 82 | #define STM32_ETHADDR_5 0x46 83 | 84 | /******************************************************************************/ 85 | /* Local IP and UDP configuration */ 86 | /******************************************************************************/ 87 | #define IP(A,B,C,D) htonl(A<<24 | B<<16 | C<<8 | D) 88 | 89 | #define STM32_IPADDR IP(192, 168, 1, 60) 90 | #define STM32_GATEWAY IP(192, 168, 1, 1) 91 | #define STM32_NETMASK IP(255, 255, 255, 0) 92 | 93 | #define STM32_PORT 50001 94 | 95 | /******************************************************************************/ 96 | /* Remote Device Configuration */ 97 | /******************************************************************************/ 98 | #define REMOTE_IP IP(192, 168, 1, 154) 99 | #define REMOTE_PORT 50002 100 | 101 | void ipInit(void); 102 | void ipTransmitRandomLoop(void); 103 | void debugSerialPrint(const char * fmt, ...); 104 | 105 | #endif /* _PROJECT_H_ */ 106 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/random.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | 27 | #include "ch.h" 28 | #include "hal.h" 29 | #include "random.h" 30 | #include "project.h" 31 | 32 | static struct { 33 | 34 | struct { 35 | mutex_t mutex; 36 | } sync; 37 | 38 | #if RANDOM_STATS 39 | struct { 40 | uint32_t hwDataReady; 41 | uint32_t hwSeedErrors; 42 | uint32_t hwClockErrors; 43 | } stats; 44 | #endif 45 | 46 | } rngMgmt; 47 | 48 | int randomInit(void) 49 | { 50 | chMtxObjectInit(&rngMgmt.sync.mutex); 51 | 52 | RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; 53 | RNG->CR |= RNG_CR_RNGEN; 54 | 55 | return 0; 56 | } 57 | 58 | int randomShutdown(void) 59 | { 60 | RNG->CR &= ~(RNG_CR_RNGEN | RNG_CR_IE); 61 | RCC->AHB2ENR &= ~RCC_AHB2ENR_RNGEN; 62 | 63 | return 0; 64 | } 65 | 66 | int randomGet(uint32_t *random) 67 | { 68 | uint32_t remainingTries = 200; 69 | 70 | chMtxLock(&rngMgmt.sync.mutex); 71 | while (remainingTries--) 72 | { 73 | if (RNG->SR & RNG_SR_CEIS) 74 | { 75 | #if RANDOM_STATS 76 | rngMgmt.stats.hwClockErrors++; 77 | #endif 78 | RNG->SR &= ~RNG_SR_CEIS; 79 | chMtxUnlock(&rngMgmt.sync.mutex); 80 | return -2; 81 | } 82 | 83 | if (RNG->SR & RNG_SR_SEIS) 84 | { 85 | #if RANDOM_STATS 86 | rngMgmt.stats.hwSeedErrors++; 87 | #endif 88 | RNG->SR &= ~RNG_SR_SEIS; 89 | 90 | /* Reinitialise the Random Number Generator and hopefully everything 91 | * will be OK next time around */ 92 | RNG->CR &= ~RNG_CR_RNGEN; 93 | RNG->CR |= RNG_CR_RNGEN; 94 | chMtxUnlock(&rngMgmt.sync.mutex); 95 | return -3; 96 | } 97 | 98 | if (RNG->SR & RNG_SR_DRDY) 99 | { 100 | #if RANDOM_STATS 101 | rngMgmt.stats.hwDataReady++; 102 | #endif 103 | *random = RNG->DR; 104 | chMtxUnlock(&rngMgmt.sync.mutex); 105 | return 0; 106 | } 107 | 108 | chThdYield(); 109 | } 110 | 111 | chMtxUnlock(&rngMgmt.sync.mutex); 112 | 113 | return -1; 114 | } 115 | 116 | 117 | -------------------------------------------------------------------------------- /test/true_random_number_generator/src/random.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2016, Alan Barr 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | *******************************************************************************/ 26 | #ifndef __RANDOM_H__ 27 | #define __RANDOM_H__ 28 | 29 | #include 30 | 31 | #ifndef RANDOM_STATS 32 | #define RANDOM_STATS 0 33 | #endif 34 | 35 | int randomInit(void); 36 | int randomShutdown(void); 37 | int randomGet(uint32_t *random); 38 | 39 | #endif /* Header Guard */ 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/true_random_number_generator/utils/file_to_png.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import argparse 29 | import os 30 | import sys 31 | from PIL import Image 32 | 33 | def colour_image(input_file_name, width, height): 34 | 35 | binary = get_input_data(input_file_name, 36 | width * height * 3) 37 | 38 | i = Image.new("RGB", (width, height), "white") 39 | pix = i.load() 40 | 41 | index = 0 42 | for w in range(width): 43 | for h in range(height): 44 | pix[w, h] = (binary[index], 45 | binary[index+1], 46 | binary[index+2]) 47 | index += 3 48 | 49 | return i 50 | 51 | def bw_image(input_file_name, width, height): 52 | 53 | binary = get_input_data(input_file_name, 54 | width * height) 55 | 56 | i = Image.new("1", (width, height), "white") 57 | pix = i.load() 58 | 59 | index = 0 60 | for w in range(width): 61 | for h in range(height): 62 | pix[w, h] = binary[index] & 1 63 | index += 1 64 | 65 | return i 66 | 67 | def get_input_data(input_file, number_bytes): 68 | 69 | try: 70 | file_stats = os.stat(input_file) 71 | except FileNotFoundError: 72 | print("Input file does not exist.", file=sys.stderr) 73 | exit(1) 74 | 75 | if file_stats.st_size < number_bytes: 76 | print("Input file too small to generate desired output.", file=sys.stderr) 77 | exit(1) 78 | 79 | file_handle = open(input_file, "rb") 80 | data = file_handle.read(number_bytes) 81 | file_handle.close() 82 | 83 | return data 84 | 85 | if __name__ == "__main__": 86 | 87 | parser = argparse.ArgumentParser(description= 88 | """ 89 | Reads a file and presents its binary information as an image 90 | file. 91 | 92 | When using the monochrome output option, only the lowest bit of each 93 | byte is used to represt a pixel.""") 94 | 95 | parser.add_argument("--input", 96 | nargs=1, 97 | help="Input file.") 98 | 99 | parser.add_argument("--output", 100 | nargs=1, 101 | help="Output image.") 102 | 103 | parser.add_argument("--type", 104 | nargs=1, 105 | help="Colour or monochrome output format. " 106 | "Defaults to \"colour\".", 107 | default=["colour"], 108 | choices=("colour", "monochrome")) 109 | 110 | parser.add_argument("--height", 111 | nargs=1, 112 | help="Output image height in pixels.", 113 | default=[1080], 114 | type=int) 115 | 116 | parser.add_argument("--width", 117 | nargs=1, 118 | help="Output image width in pixels.", 119 | default=[1920], 120 | type=int) 121 | 122 | cli_args = parser.parse_args() 123 | 124 | ################################################################################ 125 | 126 | if cli_args.type[0] == "colour": 127 | image = colour_image(cli_args.input[0], 128 | cli_args.width[0], 129 | cli_args.height[0]) 130 | else: 131 | image = bw_image(cli_args.input[0], 132 | cli_args.width[0], 133 | cli_args.height[0]) 134 | 135 | image.save(cli_args.output[0], "PNG") 136 | 137 | -------------------------------------------------------------------------------- /test/true_random_number_generator/utils/gdb_openocd.cfg: -------------------------------------------------------------------------------- 1 | # Load into GDB with -x command line argument. 2 | 3 | set height 0 4 | 5 | set print elements 0 6 | set print array on 7 | set print pretty on 8 | 9 | target remote localhost:3333 10 | monitor halt 11 | monitor reset 12 | 13 | make -j3 14 | file build/test.elf 15 | load 16 | 17 | continue 18 | 19 | -------------------------------------------------------------------------------- /test/true_random_number_generator/utils/random_receiver.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2016, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import socket 29 | import time 30 | import argparse 31 | import sys 32 | import signal 33 | 34 | exit_signalled = False 35 | 36 | class UdpLogger(object): 37 | 38 | def __init__(self, 39 | socket = None, 40 | max_bytes = None, 41 | write_to_file = None): 42 | 43 | self.duration = 0 44 | self.socket = socket 45 | self.rx_packets = 0 46 | self.rx_bytes = 0 47 | 48 | if (write_to_file != None): 49 | self.out_file = open(write_to_file, "wb") 50 | else: 51 | self.out_file = open(sys.stdout.fileno(), "wb") 52 | 53 | self.target_bytes = int(max_bytes) 54 | 55 | def limited_loop(self): 56 | 57 | while self.rx_bytes < self.target_bytes: 58 | 59 | try: 60 | data_bytes, (src_ip, src_port) = sock.recvfrom(65535) 61 | except socket.error: 62 | continue 63 | 64 | self.out_file.write(data_bytes[0:self.target_bytes - self.rx_bytes]) 65 | 66 | self.rx_packets += 1 67 | self.rx_bytes += len(data_bytes) 68 | 69 | def infinate_loop(self): 70 | 71 | while exit_signalled == False: 72 | 73 | try: 74 | data_bytes, (src_ip, src_port) = sock.recvfrom(65535) 75 | except socket.error: 76 | continue 77 | 78 | try: 79 | self.out_file.write(data_bytes) 80 | except BrokenPipeError: 81 | return 82 | 83 | self.rx_packets += 1 84 | self.rx_bytes += len(data_bytes) 85 | 86 | 87 | def run(self): 88 | started = time.time() 89 | 90 | if self.target_bytes == 0: 91 | self.infinate_loop() 92 | else: 93 | self.limited_loop() 94 | 95 | ended = time.time() 96 | self.duration = ended - started 97 | 98 | def get_duration(self): 99 | return self.duration 100 | 101 | def get_rx_bytes(self): 102 | return self.rx_bytes 103 | 104 | def get_rx_packets(self): 105 | return self.rx_packets 106 | 107 | 108 | ################################################################################ 109 | def print_stats(udp_class): 110 | sys.stderr.write("\n############################\n") 111 | sys.stderr.write("Duration (s): " + str(udp_class.get_duration()) + "\n") 112 | sys.stderr.write("Packets Rx: " + str(udp_class.get_rx_packets()) + "\n") 113 | sys.stderr.write("Bytes Rx (B): " + str(udp_class.get_rx_bytes()) + "\n") 114 | 115 | ################################################################################ 116 | 117 | def sig_int_handler(signal, frame): 118 | global exit_signalled 119 | sys.stderr.write('Exiting...') 120 | exit_signalled = True 121 | 122 | if __name__ == "__main__": 123 | 124 | parser = argparse.ArgumentParser(description= 125 | """ 126 | Logs a stream of UDP packets either to stdout or a file. 127 | """) 128 | 129 | parser.add_argument("--local-ip", 130 | nargs=1, 131 | help="Local IP Address to listen on.") 132 | 133 | parser.add_argument("--local-port", 134 | nargs=1, 135 | help="Local Port Number to listen on.") 136 | 137 | parser.add_argument("--file", 138 | nargs="?", 139 | help="The file to log to. If not specified, stdout is used.") 140 | 141 | parser.add_argument("--max-bytes", 142 | nargs="?", 143 | help="Specifies the maximum number of bytes to write." + 144 | "If not set, will loop infinitely.", 145 | default=0) 146 | 147 | 148 | cli_args = parser.parse_args() 149 | 150 | ################################################################################ 151 | 152 | signal.signal(signal.SIGINT, sig_int_handler) 153 | 154 | ################################################################################ 155 | 156 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 157 | sock.bind((cli_args.local_ip[0], int(cli_args.local_port[0]))) 158 | 159 | logger = UdpLogger(socket = sock, 160 | max_bytes = cli_args.max_bytes, 161 | write_to_file = cli_args.file) 162 | logger.run() 163 | 164 | print_stats(logger) 165 | 166 | sock.close() 167 | 168 | ################################################################################ 169 | -------------------------------------------------------------------------------- /utils/cscope.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | project_root=../ 4 | project_path1=${project_root}/stm32_streaming 5 | project_path2=${project_root}/board_stm32f4_dis_bb 6 | chibios_path=${project_root}/lib/ChibiOS 7 | sys_path=/usr/lib/arm-none-eabi/ 8 | 9 | files_list=./cscope.files 10 | 11 | # arguments: path, list 12 | get_c_files () 13 | { 14 | find $1 -name "*.[chxsS]" >> $2 15 | } 16 | 17 | search_chibios () 18 | { 19 | exclude_strings=( \ 20 | SPC \ 21 | SIMIA32 \ 22 | LPC \ 23 | ST_STM32373C_EVAL \ 24 | ST_STM3210C_EVAL \ 25 | OLIMEX \ 26 | MSP430 \ 27 | ST_STM32L_DISCOVERY \ 28 | MAPLEMINI_STM32_F103 \ 29 | ST_STM3210E_EVAL \ 30 | ST_STM32VL_DISCOVERY \ 31 | ST_STM3220G_EVAL \ 32 | ARMCM3-GENERIC-KERNEL \ 33 | Posix \ 34 | ARMCM4-SAM4L \ 35 | AVR \ 36 | ARMCM3-STM32L152-DISCOVERY \ 37 | Win32 \ 38 | AVR \ 39 | PPC \ 40 | AT91SAM7 \ 41 | IAR \ 42 | RVCT \ 43 | ARDUINO \ 44 | git \ 45 | testhal \ 46 | template \ 47 | GPIOv1 \ 48 | SPIv2) 49 | 50 | get_c_files $chibios_path $files_list 51 | 52 | for string in ${exclude_strings[@]} 53 | do 54 | eval sed -i "/.*$string.*/d" $files_list 55 | eval sed -i '/^$/d' $files_list 56 | done 57 | } 58 | 59 | search_sys () 60 | { 61 | get_c_files $sys_path $files_list 62 | } 63 | 64 | search_project () 65 | { 66 | get_c_files $project_path1 $files_list 67 | get_c_files $project_path2 $files_list 68 | } 69 | 70 | rm -f $files_list 71 | search_project 72 | search_chibios 73 | search_sys 74 | cscope -b -k 75 | rm -f $files_list 76 | 77 | 78 | -------------------------------------------------------------------------------- /utils/fir_design.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | ################################################################################ 3 | # Copyright (c) 2017, Alan Barr 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ################################################################################ 27 | 28 | import numpy as np 29 | import os 30 | from scipy import signal as signal 31 | from scipy.fftpack import fft 32 | import matplotlib.pyplot as plot 33 | import time 34 | 35 | ################################################################################ 36 | ##### Configuration ##### 37 | ################################################################################ 38 | 39 | dir_text = "./output/design/files/" 40 | dir_plots = "./output/design/plots/" 41 | 42 | file_c_coeff = "autogen_fir_coeffs" 43 | 44 | # Sampling frequency, Hz 45 | sampling_f = 1.024 * 10**6 46 | # Cutoff frequency, Hz 47 | cutoff_f = 6000.0 48 | # Number of taps/ coefficients for FIR filter. (Order + 1) 49 | taps_n = 256 50 | # Number of samples to be processed at once (used for generated C file.) 51 | 52 | ################################################################################ 53 | ##### Setup ##### 54 | ################################################################################ 55 | 56 | nyquist_f = sampling_f / 2.0 57 | 58 | if dir_plots and not os.path.exists(dir_plots): 59 | os.makedirs(dir_plots) 60 | 61 | header_string = "/*\n" 62 | header_string += "This is an auto-generated file.\n\n" 63 | header_string += "Generated on: %s\n\n" %(time.strftime("%Y-%m-%d %H:%M")) 64 | header_string += "Design Parameters:\n" 65 | header_string += " Sampling Frequency: %s Hz\n" %(str(sampling_f)) 66 | header_string += " Cutoff Frequency: %s Hz\n" %(str(cutoff_f)) 67 | header_string += " Taps: %s\n" %(str(taps_n)) 68 | header_string += "*/\n\n" 69 | ################################################################################ 70 | ##### Create FIR ##### 71 | ################################################################################ 72 | 73 | fir_coeff = signal.firwin(taps_n, cutoff=cutoff_f, nyq = nyquist_f) 74 | 75 | w, h = signal.freqz(fir_coeff) 76 | 77 | unnormalised_f = w * nyquist_f/np.pi 78 | unnormalised_f = unnormalised_f[0:20] 79 | 80 | fig, ax1 = plot.subplots() 81 | plot.title('FIR Response') 82 | 83 | ax1.plot(unnormalised_f, 20 * np.log10(abs(h))[0:20], 'b') 84 | ax1.set_ylabel('Amplitude [dB]', color='b') 85 | for tl in ax1.get_yticklabels(): 86 | tl.set_color('b') 87 | 88 | ax2 = ax1.twinx() 89 | ax2.plot(unnormalised_f, np.unwrap(np.angle(h))[0:20], 'g') 90 | ax2.set_ylabel('Angle [radians]', color='g') 91 | for tl in ax2.get_yticklabels(): 92 | tl.set_color('g') 93 | 94 | ax1.set_xlabel('Frequency [Hz]') 95 | 96 | plot.grid() 97 | plot.axis('tight') 98 | plot.savefig(dir_plots + "fir.png") 99 | plot.close() 100 | 101 | ################################################################################ 102 | ##### Create FIR C Files ##### 103 | ################################################################################ 104 | 105 | fir_coeff_reversed = fir_coeff[::-1] 106 | 107 | if not os.path.exists(dir_text): 108 | os.makedirs(dir_text) 109 | 110 | # Header File 111 | h_file_handle = open(dir_text + file_c_coeff + ".h","w") 112 | 113 | h_file_handle.write(header_string) 114 | h_file_handle.write("#ifndef __%s__\n" %file_c_coeff.upper()) 115 | h_file_handle.write("#define __%s__\n\n" %file_c_coeff.upper()) 116 | 117 | h_file_handle.write("#include \"arm_math.h\"\n\n") 118 | 119 | h_file_handle.write("#define FIR_COEFFS_LEN %s\n" %taps_n) 120 | 121 | h_file_handle.write("extern float32_t firCoeffs[FIR_COEFFS_LEN];\n") 122 | 123 | h_file_handle.write("\n#endif\n") 124 | h_file_handle.close() 125 | 126 | # C File 127 | file_handle = open(dir_text + file_c_coeff + ".c","w") 128 | file_handle.write(header_string) 129 | 130 | file_handle.write("#include \"" + file_c_coeff + ".h\"\n\n") 131 | 132 | # Float Coeffs 133 | file_handle.write("float32_t firCoeffs[FIR_COEFFS_LEN] = {\n") 134 | for f in fir_coeff_reversed: 135 | file_handle.write(" %.23f,\n" %f) 136 | file_handle.write("};\n\n") 137 | 138 | file_handle.close() 139 | 140 | 141 | -------------------------------------------------------------------------------- /utils/gdb_openocd.cfg: -------------------------------------------------------------------------------- 1 | # Load into GDG with -x command line argument. 2 | 3 | set print pretty on 4 | set height 0 5 | set print elements 0 6 | 7 | set logging file gdb_output.log 8 | set logging overwrite on 9 | set logging off 10 | 11 | target remote localhost:3333 12 | monitor halt 13 | monitor reset 14 | 15 | make -j3 16 | file build/streaming_mic.elf 17 | load 18 | 19 | continue 20 | 21 | --------------------------------------------------------------------------------