diff --git a/.gitignore b/.gitignore index 2c123b52..1ce91126 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ DSP_Lib_TestSuite/build/ -PythonWrapper/build/ PythonWrapper/cmsisdsp.cp36-win_amd64.pyd PythonWrapper/internal.cp36-win_amd64.pyd PythonWrapper/*.so @@ -22,7 +21,6 @@ Output/ Documentation/html/ PACK.xsd *.uvguix.* -build Documentation/html/* Doxygen/history.txt Doxygen/dsp.dxy @@ -30,3 +28,4 @@ __pycache__/ *.pyd .DS_Store .swiftpm/ +build/ diff --git a/ComputeGraph/README.md b/ComputeGraph/README.md index 026fe996..465f8b45 100644 --- a/ComputeGraph/README.md +++ b/ComputeGraph/README.md @@ -235,6 +235,8 @@ Another possibility would be to make the buffer static by redefining the macro ` Optional arguments to pass to the C API of the scheduler function +It can either use a `string` or a list of `string` where an element is an argument of the function (and should be valid `C`). + ##### codeArray (default = True) When true, the scheduling is defined as an array. Otherwise, a list of function calls is generated. @@ -305,6 +307,8 @@ In case of dynamic / asynchronous scheduling, the FIFOs may need to be bigger th For instance, a value of 10 means the FIFO will have their size updated from `oldSize` to `1.1 * oldSize` which is ` (1 + 10%)* oldSize` +If the value is a `float` instead of an `int` it will be used as is. For instance, `1.1` would increase the size by `1.1` and be equivalent to the setting `10` (for 10 percent). + ##### asyncDefaultSkip (default True) Behavior of a pure function (like CMSIS-DSP) in asynchronous mode. When `True`, the execution is skipped if the function can't be executed. If `False`, an error is raised. @@ -353,6 +357,14 @@ The `fifoClass` argument allows to choose a specific FIFO class in the generated Only the `FIFO` class is provided by default. Any new implementation must inherit from `FIFObase` +There is also an option to set the scaling factor when used in asynchronous mode: + +```python +g.connect(odd.o,debug.i,fifoScale=3.0) +``` + +When this option is set, it will be used (instead of the global setting). This must be a float. + ## How to build the examples In folder `ComputeGraph/example/build`, type the `cmake` command: diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/RingPrivate.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/RingPrivate.h deleted file mode 100644 index a9b2300c..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/RingPrivate.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: RingPrivate.h - * Description: Implementation for RTX + Keil MDK - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _RINGPRIVATE_H_ -#define _RINGPRIVATE_H_ - -/* - -Implementation for RTX + Keil MDK Event logger - -*/ - -#include -#include "arm_vsi.h" -#ifdef _RTE_ -#include "RTE_Components.h" -#endif -#include CMSIS_device_header - -#include "cmsis_os2.h" - -#include "SchedEvents.h" -/* - -RTX dependent definition - -*/ -#define RING_BEGINCRITICALSECTION() NVIC_DisableIRQ ((IRQn_Type)config->interruptID); -#define RING_ENDCRITICALSECTION() NVIC_EnableIRQ ((IRQn_Type)config->interruptID); - -#define RING_WAIT_BUFFER(TIMEOUT) osThreadFlagsWait(1,osFlagsWaitAny,(TIMEOUT)) -#define RING_HASWAITERROR(F) (F < 0) - -#define RING_RELEASE_BUFFER(THREADID) osThreadFlagsSet((osThreadId_t)(THREADID),1) - -/* Debug trace using Event Recorder */ -#define RING_DBG_USER_RESERVE_BUFFER(ID,CONF) EventRecord2 (Evt_UsrReserve, (ID), (uint32_t)(CONF)) -#define RING_DBG_USER_RELEASE_BUFFER(ID,CONF) EventRecord2 (Evt_UsrRelease, (ID), (uint32_t)(CONF)) -#define RING_DBG_USER_WAIT_BUFFER(ID,CONF) EventRecord2 (Evt_UsrWait, (ID), (uint32_t)(CONF)) -#define RING_DBG_USER_BUFFER_RELEASED(ID,CONF) EventRecord2 (Evt_UsrFree, (ID), (uint32_t)(CONF)) -#define RING_DBG_USER_STATUS(SA,SB,CONF) EventRecord4 (Evt_UsrStatus, config->SA,config->SB,(uint32_t)(CONF),0) - -#define RING_DBG_INT_RESERVE_BUFFER(ID,CONF) EventRecord2 (Evt_IntReserve, (ID), (uint32_t)(CONF)) -#define RING_DBG_INT_RELEASE_BUFFER(ID,CONF) EventRecord2 (Evt_IntRelease, (ID), (uint32_t)(CONF)) -#define RING_DBG_INT_RELEASE_USER(CONF) EventRecord2 (Evt_IntReleaseUser, (uint32_t)(CONF), 0) -#define RING_DBG_INT_STATUS(SA,SB,CONF) EventRecord4 (Evt_IntStatus, config->SA,config->SB,(uint32_t)(CONF),0) - -#define RING_DBG_ERROR(ERROR,CONF) EventRecord2 (Evt_Error, (ERROR), (uint32_t)(CONF)) - -#endif \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/SchedEvents.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/SchedEvents.h deleted file mode 100644 index bb854d00..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/CMSIS_RTOS/SchedEvents.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: SchedEvents.h - * Description: Definition of the events for the Keil MDK Event logger - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _SCHEDEVT_H -#define _SCHEDEVT_H - -/* - -Definition of Event IDs for Keil MDK EventRecorder - -*/ -#include "EventRecorder.h" - -#define EvtNodes 0x00 -#define EvtRing_User 0x01 -#define EvtRing_Int 0x02 -#define EvtRing_All 0x03 - -/* Node events */ - -#define Evt_Sink EventID (EventLevelAPI, EvtNodes, 0x00) -#define Evt_SinkVal EventID (EventLevelOp, EvtNodes, 0x01) -#define Evt_Source EventID (EventLevelAPI, EvtNodes, 0x02) - -/* User Ring Events */ -#define Evt_UsrReserve EventID (EventLevelOp, EvtRing_User, 0x00) -#define Evt_UsrRelease EventID (EventLevelOp, EvtRing_User, 0x01) -#define Evt_UsrWait EventID (EventLevelOp, EvtRing_User, 0x02) -#define Evt_UsrFree EventID (EventLevelOp, EvtRing_User, 0x03) -#define Evt_UsrStatus EventID (EventLevelDetail, EvtRing_User, 0x04) - - -/* Interrupt Ring Events */ -#define Evt_IntReserve EventID (EventLevelOp, EvtRing_Int, 0x00) -#define Evt_IntRelease EventID (EventLevelOp, EvtRing_Int, 0x01) -#define Evt_IntReleaseUser EventID (EventLevelOp, EvtRing_Int, 0x02) -#define Evt_IntStatus EventID (EventLevelDetail, EvtRing_Int, 0x03) - - -/* Other Ring Events */ -#define Evt_Error EventID (EventLevelError, EvtRing_All, 0x00) - - - -#endif \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/AudioConfig.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/AudioConfig.h deleted file mode 100644 index ad3fa942..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/AudioConfig.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _AUDIOCONFIG_H_ -#define _AUDIOCONFIG_H_ - -// <<< Use Configuration Wizard in Context Menu >>> - -// Audio Configuration for RX -#ifndef AUDIO_DRV_RX_ENABLED -#define AUDIO_DRV_RX_ENABLED 1 -#endif -// Sampling Frequency <8000=> 8000 kHz <16000=> 16000 kHz -// <44100=> 44100 kHz <48000=> 48000 kHz -#ifndef AUDIO_DRV_SAMPLINGFREQUENCY_RX -#define AUDIO_DRV_SAMPLINGFREQUENCY_RX 16000 -#endif - -// Number of samples <256=> 256 <512=> 512 <1024=> 1024 <2048=> 2048 -// Must be consistent with the settings of the Audio source -#ifndef AUDIO_DRV_NBSAMPLES_RX -#define AUDIO_DRV_NBSAMPLES_RX 2048 -#endif - -// Number of channels <1=> Mono <2=> Stereo -#ifndef AUDIO_DRV_NBCHANNELS_RX -#define AUDIO_DRV_NBCHANNELS_RX 1U -#endif - -// Channel encoding <2=> 16 Bits -#ifndef AUDIO_DRV_CHANNEL_ENCODING_RX -#define AUDIO_DRV_CHANNEL_ENCODING_RX 2U -#endif - -// - -// Audio Configuration for TX -#ifndef AUDIO_DRV_TX_ENABLED -#define AUDIO_DRV_TX_ENABLED 1 -#endif -// Sampling Frequency <8000=> 8000 kHz <16000=> 16000 kHz -// <44100=> 44100 kHz <48000=> 48000 kHz -#ifndef AUDIO_DRV_SAMPLINGFREQUENCY_TX -#define AUDIO_DRV_SAMPLINGFREQUENCY_TX 16000 -#endif - -// Number of samples <256=> 256 <512=> 512 <1024=> 1024 <2048=> 2048 -// Must be consistent with the settings of the Audio source -#ifndef AUDIO_DRV_NBSAMPLES_TX -#define AUDIO_DRV_NBSAMPLES_TX 2048 -#endif - -// Number of channels <1=> Mono <2=> Stereo -#ifndef AUDIO_DRV_NBCHANNELS_TX -#define AUDIO_DRV_NBCHANNELS_TX 1U -#endif - -// Channel encoding <2=> 16 Bits -#ifndef AUDIO_DRV_CHANNEL_ENCODING_TX -#define AUDIO_DRV_CHANNEL_ENCODING_TX 2U -#endif - -// - -// CGSTATIC_VHT_TX_RX_ORDERING: Force TX RX ordering -#define CGSTATIC_VHT_TX_RX_ORDERING 0 - -// <<< end of configuration section >>> - -#define CGSTATIC_AUDIO_CONFIG - -#endif diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/RingConfig.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/RingConfig.h deleted file mode 100644 index eff840b5..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/RingConfig.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _RINGCONFIG_H_ -#define _RINGCONFIG_H_ - -// <<< Use Configuration Wizard in Context Menu >>> - - -// Ring Buffer Configuration -// Number of buffers <2=> 2 <4=> 4 <8=> 8 <16=> 16 <32=> 32 -#ifndef RING_NBBUFS -#define RING_NBBUFS 4 -#endif -// - -// <<< end of configuration section >>> - -#if defined(CGSTATIC_AUDIO_CONFIG) -#define RING_BUFSIZE_RX (AUDIO_DRV_NBSAMPLES_RX * AUDIO_DRV_NBCHANNELS_RX * AUDIO_DRV_CHANNEL_ENCODING_RX) -#define RING_BUFSIZE_TX (AUDIO_DRV_NBSAMPLES_TX * AUDIO_DRV_NBCHANNELS_TX * AUDIO_DRV_CHANNEL_ENCODING_TX) -#endif - -#if defined(CGSTATIC_VIDEO_CONFIG) -#define RING_BUFSIZE_RX (VIDEO_DRV_WIDTH * VIDEO_DRV_HEIGHT * VIDEO_DRV_PIXEL_SIZE) -#define RING_BUFSIZE_TX 0 -#endif - -#endif diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/VideoConfig.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/VideoConfig.h deleted file mode 100644 index a77fb449..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/Config/VideoConfig.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _VIDEOCONFIG_H_ -#define _VIDEOCONFIG_H_ - -// <<< Use Configuration Wizard in Context Menu >>> - -// Video Configuration -// Width in pixels <16-640> -#ifndef VIDEO_DRV_WIDTH -#define VIDEO_DRV_WIDTH 32 -#endif - -// Height in pixels <16-640> -#ifndef VIDEO_DRV_HEIGHT -#define VIDEO_DRV_HEIGHT 32 -#endif - -// Pixel size in bytes <1=> 1 <2=> 2 -#ifndef VIDEO_DRV_PIXEL_SIZE -#define VIDEO_DRV_PIXEL_SIZE 1 -#endif - -// Frame rate <10=> 10 <25=> 25 <30=> 30 <60=> 60 -#ifndef VIDEO_DRV_FRAME_RATE -#define VIDEO_DRV_FRAME_RATE 10 -#endif - -// - - - -// <<< end of configuration section >>> - -#define CGSTATIC_VIDEO_CONFIG - -#endif diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/README.md b/ComputeGraph/cg/nodes/cpp/StreamingNodes/README.md deleted file mode 100644 index e894ca39..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Streaming Nodes - -This is an example implementation to be used with Arm Virtual Hardware (AVH). - -It is requiring headers and source files provided by AVH. - -Those files are not needed at all to use the Compute Graph. - -Those files are kept because they are used in the AVH-SystemModeling example. - -But there are simpler way to interface the compute graph to an audio interrupt. - -Those nodes are considered as deprecated. Don't use them. - -## RingBuffer - -It is a way to connect the compute graph with static flow to an audio source or sink. - -The node part is implemented in the AudioSource and AudioSink parts. - - -The main implementation is in `RingBuffer`. - - -To port it to new environments: - -- A file RingPrivate.h must be written. It is included by RingBuffer.cpp to customize some part of the implementation -- A file managing the audio interrupts must be written an interact with the Ring buffers -- The file RingConfig.h must be provided to size the buffers -- Most of the time the Ring buffer will have only 2 buffers and will be a ping-pong buffer. - diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.cpp b/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.cpp deleted file mode 100644 index ce20f84c..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: RingBuffer.cpp - * Description: Implementation of the Ring buffer. - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - -RTOS dependent definitions must be in RingPrivate.h. -Without a RingPrivate.h, this code cannot work. - - */ -#include "RingPrivate.h" -#include "RingBuffer.h" - -/* - -RTOS Integration - -*/ -#ifndef RING_BEGINCRITICALSECTION -#define RING_BEGINCRITICALSECTION() -#endif - -#ifndef RING_ENDCRITICALSECTION -#define RING_ENDCRITICALSECTION() -#endif - -#ifndef RING_WAIT_BUFFER -#define RING_WAIT_BUFFER(ID) 0 -#endif - -#ifndef RING_RELEASE_BUFFER -#define RING_RELEASE_BUFFER(THREADID) -#endif - -#ifndef RING_HASWAITERROR -#define RING_HASWAITERROR(ERR) 0 -#endif - -/* - -Debug integration - -*/ - -#ifndef RING_DBG_USER_RESERVE_BUFFER -#define RING_DBG_USER_RESERVE_BUFFER(ID,CONF) -#endif - -#ifndef RING_DBG_USER_RELEASE_BUFFER -#define RING_DBG_USER_RELEASE_BUFFER(ID,CONF) -#endif - -#ifndef RING_DBG_USER_WAIT_BUFFER -#define RING_DBG_USER_WAIT_BUFFER(ID,CONF) -#endif - -#ifndef RING_DBG_USER_BUFFER_RELEASED -#define RING_DBG_USER_BUFFER_RELEASED(ID,CONF) -#endif - -#ifndef RING_DBG_USER_STATUS -#define RING_DBG_USER_STATUS(SA,SB,CONF) -#endif - -#ifndef RING_DBG_INT_RESERVE_BUFFER -#define RING_DBG_INT_RESERVE_BUFFER(ID,CONF) -#endif - -#ifndef RING_DBG_INT_RELEASE_BUFFER -#define RING_DBG_INT_RELEASE_BUFFER(ID,CONF) -#endif - -#ifndef RING_DBG_INT_RELEASE_USER -#define RING_DBG_INT_RELEASE_USER(CONF) -#endif - -#ifndef RING_DBG_INT_STATUS -#define RING_DBG_INT_STATUS(SA,SB,CONF) -#endif - -#ifndef RING_DBG_ERROR -#define RING_DBG_ERROR(ERROR,CONF) -#endif - -/* - -Implementation - -*/ - -#define RING_SET(FIELD,BIT) (config->FIELD) |= (1 << (config->BIT)) -#define RING_CLEAR(FIELD,BIT) (config->FIELD) &= ~(1 << (config->BIT)) -#define RING_TEST(FIELD,BIT) (((config->FIELD) & (1 << (config->BIT))) != 0) - -#define RING_INC(ID) \ - config->ID++; \ - if (config->ID == config->nbBuffers)\ - { \ - config->ID=0; \ - } - -#define RING_BUSY(ID) \ - (RING_TEST(userBufferStatus,ID) || RING_TEST(intBufferStatus,ID)) - - -void ringInit(ring_config_t *config, - uint32_t nbBuffers, - uint32_t bufferSize, - uint8_t *buffer, - int interruptID, - int timeout) -{ - - config->buffer=buffer; - config->nbBuffers = nbBuffers; - config->bufferSize = bufferSize; - config->interruptBufferIDStart = 0; - config->interruptBufferIDStop = 0; - config->userBufferIDStart = 0; - config->userBufferIDStop = 0; - config->error=kNoError; - config->waiting=0; - config->timeout=timeout; - - config->interruptID = interruptID; - config->userBufferStatus = 0; - config->intBufferStatus = 0; - -} - -void ringClean(ring_config_t *config) -{ -} - -uint8_t *ringGetBufferAddress(ring_config_t *config,int id) -{ - if (id < 0) - { - return(NULL); - } - else - { - return(&config->buffer[id*config->bufferSize]); - } -} - -int ringInterruptReserveBuffer(ring_config_t *config) -{ - RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config); - if (config->error) - { - return(-1); - } - - /* Try to reserve a buffer */ - if (RING_BUSY(interruptBufferIDStop)) - { - /* If buffer is already used then kErrorOverflowUnderflow*/ - config->error=kErrorOverflowUnderflow; - RING_DBG_ERROR(config->error,config); - return(-1); - } - else - { - RING_DBG_INT_RESERVE_BUFFER(config->interruptBufferIDStop,config); - RING_SET(intBufferStatus,interruptBufferIDStop); - RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config); - int id=config->interruptBufferIDStop; - RING_INC(interruptBufferIDStop); - return(id); - } -} - -void ringInterruptReleaseBuffer(ring_config_t *config,void *threadId) -{ - RING_DBG_INT_STATUS(userBufferStatus,intBufferStatus,config); - if (config->error) - { - return; - } - if (config->interruptBufferIDStart != config->interruptBufferIDStop) - { - RING_DBG_INT_RELEASE_BUFFER(config->interruptBufferIDStart,config); - RING_CLEAR(intBufferStatus,interruptBufferIDStart); - /* Send release message in case the thread may be waiting */ - if (config->interruptBufferIDStart == config->userBufferIDStop) - { - if (config->waiting) - { - RING_DBG_INT_RELEASE_USER(config); - RING_RELEASE_BUFFER(threadId); - } - } - RING_INC(interruptBufferIDStart); - } -} - -int ringUserReserveBuffer(ring_config_t *config) -{ - RING_BEGINCRITICALSECTION(); - RING_DBG_USER_STATUS(userBufferStatus,intBufferStatus,config); - if (config->error) - { - RING_ENDCRITICALSECTION(); - return(-1); - } - /* If buffer is busy we wait*/ - if (RING_BUSY(userBufferIDStop)) - { - config->waiting=1; - RING_DBG_USER_WAIT_BUFFER(config->userBufferIDStop,config); - RING_ENDCRITICALSECTION(); - - int err = RING_WAIT_BUFFER(config->timeout); - - RING_BEGINCRITICALSECTION(); - RING_DBG_USER_BUFFER_RELEASED(config->userBufferIDStop,config); - if (RING_HASWAITERROR(err)) - { - RING_DBG_ERROR(err,config); - config->error=kTimeout; - return(-1); - } - - } - - RING_DBG_USER_RESERVE_BUFFER(config->userBufferIDStop,config); - RING_SET(userBufferStatus,userBufferIDStop); - int id=config->userBufferIDStop; - RING_INC(userBufferIDStop); - - RING_ENDCRITICALSECTION(); - - return(id); -} - -void ringUserReleaseBuffer(ring_config_t *config) -{ - RING_BEGINCRITICALSECTION(); - RING_DBG_USER_STATUS(userBufferStatus,intBufferStatus,config); - if (config->error) - { - RING_ENDCRITICALSECTION(); - return; - } - if (config->userBufferIDStart != config->userBufferIDStop) - { - RING_DBG_USER_RELEASE_BUFFER(config->userBufferIDStart,config); - RING_CLEAR(userBufferStatus,userBufferIDStart); - RING_INC(userBufferIDStart); - } - - RING_ENDCRITICALSECTION(); -} diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.h deleted file mode 100644 index eb3870c8..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingBuffer.h +++ /dev/null @@ -1,125 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: RingBuffer.h - * Description: Ring buffer to connect the compute graph with static flow to audio sources and sinks - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _RINGBUFFER_H_ -#define _RINGBUFFER_H_ - - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef enum { - kErrorOverflowUnderflow=-1, - kTimeout=-2, - kErrorHWOverlowUnderflow=-3, - kNoError=0 -} ring_error_t; - -typedef struct { - uint8_t *buffer; - uint32_t userBufferStatus; - uint32_t intBufferStatus; - - int32_t nbBuffers; - uint32_t bufferSize; - - int32_t interruptBufferIDStart; - int32_t interruptBufferIDStop; - int32_t userBufferIDStart; - int32_t userBufferIDStop; - int32_t waiting; - int timeout; - ring_error_t error; - int interruptID; -} ring_config_t; - - - /** - * @brief Ring buffer initialization - * @param[in, out] buf ring buffer configuration. - * @param[in] nbBuffers number of buffers (max 32) - * @param[in] bufferSize size of each buffer in bytes - * @param[in] buffer array for the buffer storage (bufferSize*nbBuffers) - * @param[in] interruptID interrupt ID - * @param[in] timeout timeout (meaning is RTOS dependent) - * @return Nothing - */ - void ringInit(ring_config_t *buf, - uint32_t nbBuffers, - uint32_t bufferSize, - uint8_t *buffer, - int interruptID, - int timeout); - - - -void ringClean(ring_config_t *buf); - -/* - -Try to reserve a buffer from a user thread. - -*/ -int ringUserReserveBuffer(ring_config_t *buf); - -/* - -Release a buffer from user htread - -*/ -void ringUserReleaseBuffer(ring_config_t *buf); - -/* - -Reserve a buffer from interrupt - -*/ -int ringInterruptReserveBuffer(ring_config_t *buf); - -/* - -Release a buffer from interrupt - -*/ -void ringInterruptReleaseBuffer(ring_config_t *buf,void *threadId); - -/* - -Get address of buffer - -*/ - -uint8_t *ringGetBufferAddress(ring_config_t *buf,int id); - - -#ifdef __cplusplus -} -#endif - -#endif /* #ifndef _RINGBUFFER_H_*/ \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.cpp b/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.cpp deleted file mode 100644 index f4853c9f..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: RingInit.cpp - * Description: Initialization of the ring data structure for an audio source - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "arm_math.h" -#include "RingConfig.h" -#include "RingInit.h" -#include "RingBuffer.h" - - - - -void initRing(ring_config_t *ringConfigRX, - uint8_t *rxBuffer, - uint32_t bufSizeRX, - int rxInterruptID, - ring_config_t *ringConfigTX, - uint8_t *txBuffer, - uint32_t bufSizeTX, - int txInterruptID, - int timeOut) -{ - /* Initialization of the ring buffer data structure */ - if (ringConfigRX != NULL) - { - ringInit(ringConfigRX,RING_NBBUFS,bufSizeRX,rxBuffer,rxInterruptID,timeOut); - } - - if (ringConfigTX != NULL) - { - ringInit(ringConfigTX,RING_NBBUFS,bufSizeTX,txBuffer,txInterruptID,timeOut); - } - -} \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.h deleted file mode 100644 index 9e4814df..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/RingBuffer/RingInit.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: RingInit.h - * Description: API to initialize the ring buffer - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _RINGINIT_H -#define _RINGINIT_H - - - -#include "RingBuffer.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -extern ring_config_t ringConfigRX; -extern ring_config_t ringConfigTX; - -void initRing(ring_config_t *ringConfigRX, - uint8_t *rxBuffer, - uint32_t bufSizeRX, - int rxInterruptID, - ring_config_t *ringConfigTX, - uint8_t *txBuffer, - uint32_t bufSizeTX, - int txInterruptID, - int timeOut); - -#ifdef __cplusplus -} - - -#endif -#endif diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/AudioInterrupt.cpp b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/AudioInterrupt.cpp deleted file mode 100644 index 273963ab..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/AudioInterrupt.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include "audio_drv.h" -#include "arm_vsi.h" -#ifdef _RTE_ -#include "RTE_Components.h" -#endif -#include CMSIS_device_header - -#include "cmsis_os2.h" - - - -#include "RingBuffer.h" - -#include "arm_math.h" - -#include "SchedEvents.h" -#include "AudioConfig.h" -#include "RingConfig.h" - -#include "RingInit.h" - -extern osThreadId_t gStreamingThreadID; - -// Number of bytes read by DMA -#define AUDIO_BLOCK_SIZE_RX RING_BUFSIZE_RX -#define AUDIO_BLOCK_SIZE_TX RING_BUFSIZE_TX - -// Number of DMA blocks -#define AUDIO_DMA_NB_BLOCKS RING_NBBUFS - - - - -#if AUDIO_DRV_RX_ENABLED -extern ring_config_t ringConfigRX; - -#ifdef __FVP_PY -__attribute__((section(".ARM.__at_0x90000000"))) -#endif -#if CGSTATIC_VHT_TX_RX_ORDERING -__ALIGNED(16) static uint8_t dmaRX[AUDIO_BLOCK_SIZE_RX]; -int rxCount=0; -#endif -__ALIGNED(16) static uint8_t audio_bufferRX[AUDIO_DMA_NB_BLOCKS*AUDIO_BLOCK_SIZE_RX]; -static uint8_t *reservedBufRX=NULL; -#endif - -#if AUDIO_DRV_TX_ENABLED -extern ring_config_t ringConfigTX; - -#ifdef __FVP_PY -__attribute__((section(".ARM.__at_0x9FFF0000"))) -#endif -#if CGSTATIC_VHT_TX_RX_ORDERING -__ALIGNED(16) static uint8_t dmaTX[AUDIO_BLOCK_SIZE_TX]; -int txCount=0; -#endif -__ALIGNED(16) static uint8_t audio_bufferTX[AUDIO_DMA_NB_BLOCKS*AUDIO_BLOCK_SIZE_TX]; -static uint8_t *reservedBufTX=NULL; -#endif - -uint8_t* AudioRXBuffer() -{ -#if AUDIO_DRV_RX_ENABLED - return(audio_bufferRX); -#else - return(NULL); -#endif -} - -uint8_t* AudioTXBuffer() -{ -#if AUDIO_DRV_TX_ENABLED - return(audio_bufferTX); -#else - return(NULL); -#endif -} - -static void AudioEvent (uint32_t event) { - -#if AUDIO_DRV_RX_ENABLED - if (event & AUDIO_DRV_EVENT_RX_DATA) - { - - #if CGSTATIC_VHT_TX_RX_ORDERING - memcpy(reservedBufRX,dmaRX,RING_BUFSIZE_RX); - (void)AudioDrv_Control(AUDIO_DRV_CONTROL_RX_DISABLE); - (void)AudioDrv_Control(AUDIO_DRV_CONTROL_TX_ENABLE); - #endif - ringInterruptReleaseBuffer(&ringConfigRX,(void *)gStreamingThreadID); - int reservedRX=ringInterruptReserveBuffer(&ringConfigRX); - reservedBufRX=ringGetBufferAddress(&ringConfigRX,reservedRX); - - } -#endif - -#if AUDIO_DRV_TX_ENABLED - if (event & AUDIO_DRV_EVENT_TX_DATA) - { - #if CGSTATIC_VHT_TX_RX_ORDERING - memcpy(dmaTX,reservedBufTX,RING_BUFSIZE_TX); - (void)AudioDrv_Control(AUDIO_DRV_CONTROL_TX_DISABLE); - (void)AudioDrv_Control(AUDIO_DRV_CONTROL_RX_ENABLE); - #endif - ringInterruptReleaseBuffer(&ringConfigTX,(void *)gStreamingThreadID); - int reservedTX=ringInterruptReserveBuffer(&ringConfigTX); - reservedBufTX=ringGetBufferAddress(&ringConfigTX,reservedTX); - } -#endif -} - -int32_t AudioDrv_Setup(void) { - int32_t ret; - - ret = AudioDrv_Initialize(AudioEvent); - if (ret != 0) { - return ret; - } - -#if AUDIO_DRV_RX_ENABLED - - ret = AudioDrv_Configure(AUDIO_DRV_INTERFACE_RX, - AUDIO_DRV_NBCHANNELS_RX, /* single channel */ - 8U * AUDIO_DRV_CHANNEL_ENCODING_RX, /* 16 sample bits */ - static_cast(AUDIO_DRV_SAMPLINGFREQUENCY_RX)); - if (ret != 0) { - return ret; - } - - /* Work because user process not started yet - */ - - int reservedRX=ringInterruptReserveBuffer(&ringConfigRX); - reservedBufRX=ringGetBufferAddress(&ringConfigRX,reservedRX); - -#if CGSTATIC_VHT_TX_RX_ORDERING - ret = AudioDrv_SetBuf(AUDIO_DRV_INTERFACE_RX, - dmaRX, 1,AUDIO_BLOCK_SIZE_RX); -#else - ret = AudioDrv_SetBuf(AUDIO_DRV_INTERFACE_RX, - audio_bufferRX, AUDIO_DMA_NB_BLOCKS,AUDIO_BLOCK_SIZE_RX); -#endif - if (ret != 0) { - return ret; - } - -#if !CGSTATIC_VHT_TX_RX_ORDERING - ret = AudioDrv_Control(AUDIO_DRV_CONTROL_RX_ENABLE); - if (ret != 0) { - return ret; - } -#endif - -#endif /* AUDIO_DRV_RX_ENABLED */ - -#if AUDIO_DRV_TX_ENABLED - ret = AudioDrv_Configure(AUDIO_DRV_INTERFACE_TX, - AUDIO_DRV_NBCHANNELS_TX, /* single channel */ - 8U * AUDIO_DRV_CHANNEL_ENCODING_TX, /* 16 sample bits */ - static_cast(AUDIO_DRV_SAMPLINGFREQUENCY_TX)); - if (ret != 0) { - return ret; - } - - /* Work because user process not started yet - */ - - /* dataflow must be 1 packet ahead of the TX interrupt*/ - ringUserReserveBuffer(&ringConfigTX); - ringUserReleaseBuffer(&ringConfigTX); - - ringUserReserveBuffer(&ringConfigTX); - ringUserReleaseBuffer(&ringConfigTX); - - int reservedTX=ringInterruptReserveBuffer(&ringConfigTX); - reservedBufTX=ringGetBufferAddress(&ringConfigTX,reservedTX); - -#if CGSTATIC_VHT_TX_RX_ORDERING - ret = AudioDrv_SetBuf(AUDIO_DRV_INTERFACE_TX, - dmaTX, 1 ,AUDIO_BLOCK_SIZE_TX); -#else - ret = AudioDrv_SetBuf(AUDIO_DRV_INTERFACE_TX, - audio_bufferTX, AUDIO_DMA_NB_BLOCKS,AUDIO_BLOCK_SIZE_TX); -#endif - - if (ret != 0) { - return ret; - } - - ret = AudioDrv_Control(AUDIO_DRV_CONTROL_TX_ENABLE); - if (ret != 0) { - return ret; - } - -#endif /* AUDIO_DRV_TX_ENABLED */ - - - return 0; -} - diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.c b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.c deleted file mode 100644 index d3703078..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. All rights reserved. - */ - -#include -#include "audio_drv.h" -#include "arm_vsi.h" -#ifdef _RTE_ -#include "RTE_Components.h" -#endif -#include CMSIS_device_header - -/* Audio Peripheral definitions */ -#define AudioO ARM_VSI1 /* Audio Output access struct */ -#define AudioO_IRQn ARM_VSI1_IRQn /* Audio Output Interrupt number */ -#define AudioO_Handler ARM_VSI1_Handler /* Audio Output Interrupt handler */ -#define AudioI ARM_VSI0 /* Audio Input access struct */ -#define AudioI_IRQn ARM_VSI0_IRQn /* Audio Input Interrupt number */ -#define AudioI_Handler ARM_VSI0_Handler /* Audio Input Interrupt handler */ - -/* Audio Peripheral registers */ -#define CONTROL Regs[0] /* Control receiver */ -#define CHANNELS Regs[1] /* Number of channels */ -#define SAMPLE_BITS Regs[2] /* Sample number of bits (8..32) */ -#define SAMPLE_RATE Regs[3] /* Sample rate (samples per second) */ -#define STOP_SIMULATION Regs[4] /* Stop audio simulation */ - -/* Audio Control register definitions */ -#define CONTROL_ENABLE_Pos 0U /* CONTROL: ENABLE Position */ -#define CONTROL_ENABLE_Msk (1UL << CONTROL_ENABLE_Pos) /* CONTROL: ENABLE Mask */ - -/* Driver State */ -static uint8_t Initialized = 0U; - -/* Event Callback */ -static AudioDrv_Event_t CB_Event = NULL; - -/* Audio Output Interrupt Handler */ -void AudioO_Handler (void) { - - AudioO->IRQ.Clear = 0x00000001U; - __DSB(); - __ISB(); - if (CB_Event != NULL) { - CB_Event(AUDIO_DRV_EVENT_TX_DATA); - } -} - -/* Audio Input Interrupt Handler */ -void AudioI_Handler (void) { - - AudioI->IRQ.Clear = 0x00000001U; - __DSB(); - __ISB(); - if (CB_Event != NULL) { - CB_Event(AUDIO_DRV_EVENT_RX_DATA); - } -} - - - -/* Initialize Audio Interface */ -int32_t AudioDrv_Initialize (AudioDrv_Event_t cb_event) { - - CB_Event = cb_event; - - /* Initialize Audio Output peripheral */ - AudioO->Timer.Control = 0U; - AudioO->DMA.Control = 0U; - AudioO->IRQ.Clear = 0x00000001U; - AudioO->IRQ.Enable = 0x00000001U; - AudioO->CONTROL = 0U; - - /* Initialize Audio Input peripheral */ - AudioI->Timer.Control = 0U; - AudioI->DMA.Control = 0U; - AudioI->IRQ.Clear = 0x00000001U; - AudioI->IRQ.Enable = 0x00000001U; - AudioI->CONTROL = 0U; - - /* Enable peripheral interrupts */ -//NVIC_EnableIRQ(AudioO_IRQn); - NVIC->ISER[(((uint32_t)AudioO_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)AudioO_IRQn) & 0x1FUL)); -//NVIC_EnableIRQ(AudioI_IRQn); - NVIC->ISER[(((uint32_t)AudioI_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)AudioI_IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - - Initialized = 1U; - - return AUDIO_DRV_OK; -} - -/* De-initialize Audio Interface */ -int32_t AudioDrv_Uninitialize (void) { - - /* Disable peripheral interrupts */ -//NVIC_DisableIRQ(AudioO_IRQn); - NVIC->ICER[(((uint32_t)AudioO_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)AudioO_IRQn) & 0x1FUL)); -//NVIC_DisableIRQ(AudioI_IRQn); - NVIC->ICER[(((uint32_t)AudioI_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)AudioI_IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - - /* De-initialize Audio Output peripheral */ - AudioO->Timer.Control = 0U; - AudioO->DMA.Control = 0U; - AudioO->IRQ.Clear = 0x00000001U; - AudioO->IRQ.Enable = 0x00000000U; - AudioO->CONTROL = 0U; - - /* De-initialize Audio Input peripheral */ - AudioI->Timer.Control = 0U; - AudioI->DMA.Control = 0U; - AudioI->IRQ.Clear = 0x00000001U; - AudioI->IRQ.Enable = 0x00000000U; - AudioI->CONTROL = 0U; - - Initialized = 0U; - - return AUDIO_DRV_OK; -} - -/* Configure Audio Interface */ -int32_t AudioDrv_Configure (uint32_t interface, uint32_t channels, uint32_t sample_bits, uint32_t sample_rate) { - uint32_t format; - - if (Initialized == 0U) { - return AUDIO_DRV_ERROR; - } - - if ((channels < 1U) || - (channels > 32U) || - (sample_bits < 8U) || - (sample_bits > 32U) || - (sample_rate == 0U)) { - return AUDIO_DRV_ERROR_PARAMETER; - } - - switch (interface) { - case AUDIO_DRV_INTERFACE_TX: - if ((AudioO->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - return AUDIO_DRV_ERROR; - } - AudioO->CHANNELS = channels; - AudioO->SAMPLE_BITS = sample_bits; - AudioO->SAMPLE_RATE = sample_rate; - break; - case AUDIO_DRV_INTERFACE_RX: - if ((AudioI->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - return AUDIO_DRV_ERROR; - } - AudioI->CHANNELS = channels; - AudioI->SAMPLE_BITS = sample_bits; - AudioI->SAMPLE_RATE = sample_rate; - break; - default: - return AUDIO_DRV_ERROR_PARAMETER; - } - - return AUDIO_DRV_OK; -} - -/* Set Audio Interface buffer */ -int32_t AudioDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size) { - - if (Initialized == 0U) { - return AUDIO_DRV_ERROR; - } - - switch (interface) { - case AUDIO_DRV_INTERFACE_TX: - if ((AudioO->DMA.Control & ARM_VSI_DMA_Enable_Msk) != 0U) { - return AUDIO_DRV_ERROR; - } - AudioO->DMA.Address = (uint32_t)buf; - AudioO->DMA.BlockNum = block_num; - AudioO->DMA.BlockSize = block_size; - break; - case AUDIO_DRV_INTERFACE_RX: - if ((AudioI->DMA.Control & ARM_VSI_DMA_Enable_Msk) != 0U) { - return AUDIO_DRV_ERROR; - } - AudioI->DMA.Address = (uint32_t)buf; - AudioI->DMA.BlockNum = block_num; - AudioI->DMA.BlockSize = block_size; - break; - default: - return AUDIO_DRV_ERROR_PARAMETER; - } - - return AUDIO_DRV_OK; -} - -/* Control Audio Interface */ -int32_t AudioDrv_Control (uint32_t control) { - uint32_t sample_size; - uint32_t sample_rate; - uint32_t block_size; - - if (Initialized == 0U) { - return AUDIO_DRV_ERROR; - } - - if ((control & AUDIO_DRV_CONTROL_TX_DISABLE) != 0U) { - AudioO->Timer.Control = 0U; - AudioO->DMA.Control = 0U; - AudioO->CONTROL = 0U; - } else if ((control & AUDIO_DRV_CONTROL_TX_ENABLE) != 0U) { - AudioO->CONTROL = CONTROL_ENABLE_Msk; - AudioO->DMA.Control = ARM_VSI_DMA_Direction_M2P | - ARM_VSI_DMA_Enable_Msk; - sample_size = AudioO->CHANNELS * ((AudioO->SAMPLE_BITS + 7U) / 8U); - sample_rate = AudioO->SAMPLE_RATE; - if ((sample_size == 0U) || (sample_rate == 0U)) { - AudioO->Timer.Interval = 0xFFFFFFFFU; - } else { - block_size = AudioO->DMA.BlockSize; - AudioO->Timer.Interval = (1000000U * (block_size / sample_size)) / sample_rate; - } - AudioO->Timer.Control = ARM_VSI_Timer_Trig_DMA_Msk | - ARM_VSI_Timer_Trig_IRQ_Msk | - ARM_VSI_Timer_Periodic_Msk | - ARM_VSI_Timer_Run_Msk; - } - - if ((control & AUDIO_DRV_CONTROL_RX_DISABLE) != 0U) { - AudioI->Timer.Control = 0U; - AudioI->DMA.Control = 0U; - AudioI->CONTROL = 0U; - } else if ((control & AUDIO_DRV_CONTROL_RX_ENABLE) != 0U) { - AudioI->CONTROL = CONTROL_ENABLE_Msk; - AudioI->DMA.Control = ARM_VSI_DMA_Direction_P2M | - ARM_VSI_DMA_Enable_Msk; - sample_size = AudioI->CHANNELS * ((AudioI->SAMPLE_BITS + 7U) / 8U); - sample_rate = AudioI->SAMPLE_RATE; - if ((sample_size == 0U) || (sample_rate == 0U)) { - AudioI->Timer.Interval = 0xFFFFFFFFU; - } else { - block_size = AudioI->DMA.BlockSize; - AudioI->Timer.Interval = (1000000U * (block_size / sample_size)) / sample_rate; - } - AudioI->Timer.Control = ARM_VSI_Timer_Trig_DMA_Msk | - ARM_VSI_Timer_Trig_IRQ_Msk | - ARM_VSI_Timer_Periodic_Msk | - ARM_VSI_Timer_Run_Msk; - } - - return AUDIO_DRV_OK; -} - -/* Get transmitted block count */ -uint32_t AudioDrv_GetTxCount (void) { - return (AudioO->Timer.Count); -} - -/* Get received block count */ -uint32_t AudioDrv_GetRxCount (void) { - return (AudioI->Timer.Count); -} - -/* Get Audio Interface status */ -AudioDrv_Status_t AudioDrv_GetStatus (void) { - AudioDrv_Status_t status; - uint32_t sr; - - if ((AudioO->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - status.tx_active = 1U; - } else { - status.tx_active = 0U; - } - - if ((AudioI->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - status.rx_active = 1U; - } else { - status.rx_active = 0U; - } - - return (status); -} - - -void AudioDrv_Stop (void) -{ - int32_t ret; - ret = AudioDrv_Control(AUDIO_DRV_CONTROL_TX_DISABLE); - ret = AudioDrv_Control(AUDIO_DRV_CONTROL_RX_DISABLE); - - AudioO->STOP_SIMULATION=1; - AudioI->STOP_SIMULATION=1; - -} \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.h deleted file mode 100644 index ed6a3b83..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/audio/audio_drv.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. All rights reserved. - */ - -#ifndef __AUDIO_DRV_H -#define __AUDIO_DRV_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -/* Audio Interface */ -#define AUDIO_DRV_INTERFACE_TX (1U) ///< Transmitter -#define AUDIO_DRV_INTERFACE_RX (2U) ///< Receiver - -/* Audio Control */ -#define AUDIO_DRV_CONTROL_TX_ENABLE (1UL << 0) ///< Enable Transmitter -#define AUDIO_DRV_CONTROL_RX_ENABLE (1UL << 1) ///< Enable Receiver -#define AUDIO_DRV_CONTROL_TX_DISABLE (1UL << 2) ///< Disable Transmitter -#define AUDIO_DRV_CONTROL_RX_DISABLE (1UL << 3) ///< Disable Receiver - -/* Audio Event */ -#define AUDIO_DRV_EVENT_TX_DATA (1UL << 0) ///< Data block transmitted -#define AUDIO_DRV_EVENT_RX_DATA (1UL << 1) ///< Data block received - -/* Return code */ -#define AUDIO_DRV_OK (0) ///< Operation succeeded -#define AUDIO_DRV_ERROR (-1) ///< Unspecified error -#define AUDIO_DRV_ERROR_BUSY (-2) ///< Driver is busy -#define AUDIO_DRV_ERROR_TIMEOUT (-3) ///< Timeout occurred -#define AUDIO_DRV_ERROR_UNSUPPORTED (-4) ///< Operation not supported -#define AUDIO_DRV_ERROR_PARAMETER (-5) ///< Parameter error - -/** -\brief Audio Status -*/ -typedef struct { - uint32_t tx_active : 1; ///< Transmitter active - uint32_t rx_active : 1; ///< Receiver active - uint32_t reserved : 30; -} AudioDrv_Status_t; - -/** - \fn AudioDrv_Event_t - \brief Audio Events callback function type: void (*AudioDrv_Event_t) (uint32_t event - \param[in] event events notification mask - \return none -*/ -typedef void (*AudioDrv_Event_t) (uint32_t event); - -uint8_t* AudioRXBuffer(); -uint8_t* AudioTXBuffer(); -extern int32_t AudioDrv_Setup(void); - -/** - \fn int32_t AudioDrv_Initialize (AudioDrv_Event_t cb_event) - \brief Initialize Audio Interface. - \param[in] cb_event pointer to \ref AudioDrv_Event_t - \return return code -*/ -int32_t AudioDrv_Initialize (AudioDrv_Event_t cb_event); - -/** - \fn void AudioDrv_Stop (void); - \brief Stop audio simulation. - \return return code -*/ -void AudioDrv_Stop (void); - -/** - \fn int32_t AudioDrv_Uninitialize (void) - \brief De-initialize Audio Interface. - \return return code -*/ -int32_t AudioDrv_Uninitialize (void); - -/** - \fn int32_t AudioDrv_Configure (uint32_t interface, uint32_t channels, uint32_t sample_bits, uint32_t sample_rate) - \brief Configure Audio Interface. - \param[in] interface audio interface - \param[in] channels number of channels - \param[in] sample_bits sample number of bits (8..32) - \param[in] sample_rate sample rate (samples per second) - \return return code -*/ -int32_t AudioDrv_Configure (uint32_t interface, uint32_t channels, uint32_t sample_bits, uint32_t sample_rate); - -/** - \fn int32_t AudioDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size) - \brief Set Audio Interface buffer. - \param[in] interface audio interface - \param[in] buf pointer to buffer for audio data - \param[in] block_num number of blocks in buffer (must be 2^n) - \param[in] block_size block size in number of samples - \return return code -*/ -int32_t AudioDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size); - -/** - \fn int32_t AudioDrv_Control (uint32_t control) - \brief Control Audio Interface. - \param[in] control operation - \return return code -*/ -int32_t AudioDrv_Control (uint32_t control); - -/** - \fn uint32_t AudioDrv_GetTxCount (void) - \brief Get transmitted block count. - \return number of transmitted blocks -*/ -uint32_t AudioDrv_GetTxCount (void); - -/** - \fn uint32_t AudioDrv_GetRxCount (void) - \brief Get received block count. - \return number of received blocks -*/ -uint32_t AudioDrv_GetRxCount (void); - -/** - \fn AudioDrv_Status_t AudioDrv_GetStatus (void) - \brief Get Audio Interface status. - \return \ref AudioDrv_Status_t -*/ -AudioDrv_Status_t AudioDrv_GetStatus (void); - -#ifdef __cplusplus -} -#endif - -#endif /* __AUDIO_DRV_H */ diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/VideoInterrupt.cpp b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/VideoInterrupt.cpp deleted file mode 100644 index d2017050..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/VideoInterrupt.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include "video_drv.h" -#include "arm_vsi.h" -#ifdef _RTE_ -#include "RTE_Components.h" -#endif -#include CMSIS_device_header - -#include "cmsis_os2.h" - - - -#include "RingBuffer.h" - -#include "arm_math.h" - -#include "SchedEvents.h" -#include "VideoConfig.h" -#include "RingConfig.h" - -#include "RingInit.h" - -extern osThreadId_t gStreamingThreadID; - -// Number of bytes read by DMA -#define VIDEO_BLOCK_SIZE RING_BUFSIZE_RX - -// Number of DMA blocks -#define VIDEO_DMA_NB_BLOCKS RING_NBBUFS - - -extern int32_t VideoDrv_Setup(void); - - -extern ring_config_t ringConfigRX; - -#ifdef __FVP_PY -__attribute__((section(".ARM.__at_0x90000000"))) -#endif -__ALIGNED(16) static uint8_t video_bufferRX[VIDEO_DMA_NB_BLOCKS*VIDEO_BLOCK_SIZE]; -static uint8_t *reservedBufRX=NULL; - - -uint8_t* VideoRXBuffer() -{ - return(video_bufferRX); -} - - -static void VideoEvent (uint32_t event) { - - if (event & VIDEO_DRV_EVENT_RX_DATA) - { - - - ringInterruptReleaseBuffer(&ringConfigRX,(void *)gStreamingThreadID); - int reservedRX=ringInterruptReserveBuffer(&ringConfigRX); - reservedBufRX=ringGetBufferAddress(&ringConfigRX,reservedRX); - - } - -} - -int32_t VideoDrv_Setup(void) { - int32_t ret; - - ret = VideoDrv_Initialize(VideoEvent); - if (ret != 0) { - return ret; - } - - - ret = VideoDrv_Configure(VIDEO_DRV_INTERFACE_RX, - 8U * VIDEO_DRV_PIXEL_SIZE, /* 16 sample bits */ - static_cast(VIDEO_DRV_FRAME_RATE*VIDEO_DRV_WIDTH*VIDEO_DRV_HEIGHT)); - if (ret != 0) { - return ret; - } - - /* Work because user process not started yet - */ - - int reservedRX=ringInterruptReserveBuffer(&ringConfigRX); - reservedBufRX=ringGetBufferAddress(&ringConfigRX,reservedRX); - - - ret = VideoDrv_SetBuf(VIDEO_DRV_INTERFACE_RX, - video_bufferRX, VIDEO_DMA_NB_BLOCKS,VIDEO_BLOCK_SIZE); - if (ret != 0) { - return ret; - } - - ret = VideoDrv_Control(VIDEO_DRV_CONTROL_RX_ENABLE); - if (ret != 0) { - return ret; - } - - - return 0; -} - diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.c b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.c deleted file mode 100644 index 1992e10e..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. All rights reserved. - */ - -#include -#include "video_drv.h" -#include "arm_vsi.h" -#ifdef _RTE_ -#include "RTE_Components.h" -#endif -#include CMSIS_device_header - -/* Video Peripheral definitions */ -#define VideoO ARM_VSI1 /* Video Output access struct */ -#define VideoO_IRQn ARM_VSI1_IRQn /* Video Output Interrupt number */ -#define VideoO_Handler ARM_VSI1_Handler /* Video Output Interrupt handler */ -#define VideoI ARM_VSI0 /* Video Input access struct */ -#define VideoI_IRQn ARM_VSI0_IRQn /* Video Input Interrupt number */ -#define VideoI_Handler ARM_VSI0_Handler /* Video Input Interrupt handler */ - -/* Video Peripheral registers */ -#define CONTROL Regs[0] /* Control receiver */ -#define SAMPLE_BITS Regs[1] /* Sample number of bits (8..32) */ -#define SAMPLE_RATE Regs[2] /* Sample rate (frame per second) */ -#define STOP_SIMULATION Regs[4] /* Stop audio simulation */ - -/* Video Control register definitions */ -#define CONTROL_ENABLE_Pos 0U /* CONTROL: ENABLE Position */ -#define CONTROL_ENABLE_Msk (1UL << CONTROL_ENABLE_Pos) /* CONTROL: ENABLE Mask */ - -/* Driver State */ -static uint8_t Initialized = 0U; - -/* Event Callback */ -static VideoDrv_Event_t CB_Event = NULL; - - -/* Video Input Interrupt Handler */ -void VideoI_Handler (void) { - - VideoI->IRQ.Clear = 0x00000001U; - __DSB(); - __ISB(); - if (CB_Event != NULL) { - CB_Event(VIDEO_DRV_EVENT_RX_DATA); - } -} - - -void VideoO_Handler (void) { - - VideoO->IRQ.Clear = 0x00000001U; - __DSB(); - __ISB(); -} - - -/* Initialize Video Interface */ -int32_t VideoDrv_Initialize (VideoDrv_Event_t cb_event) { - - CB_Event = cb_event; - - /* Initialize Video Output peripheral */ - VideoO->Timer.Control = 0U; - VideoO->DMA.Control = 0U; - VideoO->IRQ.Clear = 0x00000001U; - VideoO->IRQ.Enable = 0x00000001U; - VideoO->CONTROL = 0U; - - /* Initialize Video Input peripheral */ - VideoI->Timer.Control = 0U; - VideoI->DMA.Control = 0U; - VideoI->IRQ.Clear = 0x00000001U; - VideoI->IRQ.Enable = 0x00000001U; - VideoI->CONTROL = 0U; - - /* Enable peripheral interrupts */ - NVIC->ISER[(((uint32_t)VideoI_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)VideoI_IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - - Initialized = 1U; - - return VIDEO_DRV_OK; -} - -/* De-initialize Video Interface */ -int32_t VideoDrv_Uninitialize (void) { - - /* Disable peripheral interrupts */ - NVIC->ICER[(((uint32_t)VideoI_IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)VideoI_IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - - /* De-initialize Video Output peripheral */ - VideoO->Timer.Control = 0U; - VideoO->DMA.Control = 0U; - VideoO->IRQ.Clear = 0x00000001U; - VideoO->IRQ.Enable = 0x00000000U; - VideoO->CONTROL = 0U; - - /* De-initialize Video Input peripheral */ - VideoI->Timer.Control = 0U; - VideoI->DMA.Control = 0U; - VideoI->IRQ.Clear = 0x00000001U; - VideoI->IRQ.Enable = 0x00000000U; - VideoI->CONTROL = 0U; - - Initialized = 0U; - - return VIDEO_DRV_OK; -} - -/* Configure Video Interface */ -int32_t VideoDrv_Configure (uint32_t interface, uint32_t pixel_size, uint32_t samplerate) { - uint32_t format; - - if (Initialized == 0U) { - return VIDEO_DRV_ERROR; - } - - if ((pixel_size < 8*1U) || - (pixel_size > 8*2U)) { - return VIDEO_DRV_ERROR_PARAMETER; - } - - switch (interface) { - case VIDEO_DRV_INTERFACE_RX: - if ((VideoI->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - return VIDEO_DRV_ERROR; - } - VideoI->SAMPLE_BITS = pixel_size; - VideoI->SAMPLE_RATE = samplerate; - break; - default: - return VIDEO_DRV_ERROR_PARAMETER; - } - - return VIDEO_DRV_OK; -} - -/* Set Video Interface buffer */ -int32_t VideoDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size) { - - if (Initialized == 0U) { - return VIDEO_DRV_ERROR; - } - - switch (interface) { - case VIDEO_DRV_INTERFACE_RX: - if ((VideoI->DMA.Control & ARM_VSI_DMA_Enable_Msk) != 0U) { - return VIDEO_DRV_ERROR; - } - VideoI->DMA.Address = (uint32_t)buf; - VideoI->DMA.BlockNum = block_num; - VideoI->DMA.BlockSize = block_size; - break; - default: - return VIDEO_DRV_ERROR_PARAMETER; - } - - return VIDEO_DRV_OK; -} - -/* Control Video Interface */ -int32_t VideoDrv_Control (uint32_t control) { - uint32_t sample_size; - uint32_t sample_rate; - uint32_t block_size; - - if (Initialized == 0U) { - return VIDEO_DRV_ERROR; - } - - - - if ((control & VIDEO_DRV_CONTROL_RX_DISABLE) != 0U) { - VideoI->Timer.Control = 0U; - VideoI->DMA.Control = 0U; - VideoI->CONTROL = 0U; - } else if ((control & VIDEO_DRV_CONTROL_RX_ENABLE) != 0U) { - VideoI->CONTROL = CONTROL_ENABLE_Msk; - VideoI->DMA.Control = ARM_VSI_DMA_Direction_P2M | - ARM_VSI_DMA_Enable_Msk; - sample_size = ((VideoI->SAMPLE_BITS + 7U) / 8U); - sample_rate = VideoI->SAMPLE_RATE; - if ((sample_size == 0U) || (sample_rate == 0U)) { - VideoI->Timer.Interval = 0xFFFFFFFFU; - } else { - block_size = VideoI->DMA.BlockSize; - VideoI->Timer.Interval = (1000000U * (block_size / sample_size)) / sample_rate; - } - VideoI->Timer.Control = ARM_VSI_Timer_Trig_DMA_Msk | - ARM_VSI_Timer_Trig_IRQ_Msk | - ARM_VSI_Timer_Periodic_Msk | - ARM_VSI_Timer_Run_Msk; - } - - return VIDEO_DRV_OK; -} - -/* Get received block count */ -uint32_t VideoDrv_GetRxCount (void) { - return (VideoI->Timer.Count); -} - -/* Get Video Interface status */ -VideoDrv_Status_t VideoDrv_GetStatus (void) { - VideoDrv_Status_t status; - uint32_t sr; - - - if ((VideoI->CONTROL & CONTROL_ENABLE_Msk) != 0U) { - status.rx_active = 1U; - } else { - status.rx_active = 0U; - } - - return (status); -} - - -void VideoDrv_Stop (void) -{ - int32_t ret; - ret = VideoDrv_Control(VIDEO_DRV_CONTROL_RX_DISABLE); - - VideoI->STOP_SIMULATION=1; - -} - - diff --git a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.h b/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.h deleted file mode 100644 index 01eef286..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingNodes/VHT/video/video_drv.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. All rights reserved. - */ - -#ifndef __VIDEO_DRV_H -#define __VIDEO_DRV_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -/* Video Interface */ -#define VIDEO_DRV_INTERFACE_RX (2U) ///< Receiver - -/* Video Control */ -#define VIDEO_DRV_CONTROL_RX_ENABLE (1UL << 1) ///< Enable Receiver -#define VIDEO_DRV_CONTROL_RX_DISABLE (1UL << 3) ///< Disable Receiver - -/* Video Event */ -#define VIDEO_DRV_EVENT_RX_DATA (1UL << 1) ///< Data block received - -/* Return code */ -#define VIDEO_DRV_OK (0) ///< Operation succeeded -#define VIDEO_DRV_ERROR (-1) ///< Unspecified error -#define VIDEO_DRV_ERROR_BUSY (-2) ///< Driver is busy -#define VIDEO_DRV_ERROR_TIMEOUT (-3) ///< Timeout occurred -#define VIDEO_DRV_ERROR_UNSUPPORTED (-4) ///< Operation not supported -#define VIDEO_DRV_ERROR_PARAMETER (-5) ///< Parameter error - -/** -\brief Video Status -*/ -typedef struct { - uint32_t tx_active : 1; ///< Transmitter active - uint32_t rx_active : 1; ///< Receiver active - uint32_t reserved : 30; -} VideoDrv_Status_t; - -uint8_t* VideoRXBuffer(); -int32_t VideoDrv_Setup(void); - -/** - \fn VideoDrv_Event_t - \brief Video Events callback function type: void (*VideoDrv_Event_t) (uint32_t event - \param[in] event events notification mask - \return none -*/ -typedef void (*VideoDrv_Event_t) (uint32_t event); - -/** - \fn int32_t VideoDrv_Initialize (VideoDrv_Event_t cb_event) - \brief Initialize Video Interface. - \param[in] cb_event pointer to \ref VideoDrv_Event_t - \return return code -*/ -int32_t VideoDrv_Initialize (VideoDrv_Event_t cb_event); - -/** - \fn void VideoDrv_Stop (void); - \brief Stop audio simulation. - \return return code -*/ -void VideoDrv_Stop (void); - - -/** - \fn int32_t VideoDrv_Uninitialize (void) - \brief De-initialize Video Interface. - \return return code -*/ -int32_t VideoDrv_Uninitialize (void); - -/** - \fn int32_t VideoDrv_Configure (uint32_t interface, uint32_t channels, uint32_t sample_bits, uint32_t sample_rate) - \brief Configure Video Interface. - \param[in] interface audio interface - \param[in] pixel_size size in bytes - \param[in] samplerate samples per second - \return return code -*/ -int32_t VideoDrv_Configure (uint32_t interface, uint32_t pixel_size,uint32_t samplerate); - -/** - \fn int32_t VideoDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size) - \brief Set Video Interface buffer. - \param[in] interface audio interface - \param[in] buf pointer to buffer for audio data - \param[in] block_num number of blocks in buffer (must be 2^n) - \param[in] block_size block size in number of samples - \return return code -*/ -int32_t VideoDrv_SetBuf (uint32_t interface, void *buf, uint32_t block_num, uint32_t block_size); - -/** - \fn int32_t VideoDrv_Control (uint32_t control) - \brief Control Video Interface. - \param[in] control operation - \return return code -*/ -int32_t VideoDrv_Control (uint32_t control); - - -/** - \fn uint32_t VideoDrv_GetRxCount (void) - \brief Get received block count. - \return number of received blocks -*/ -uint32_t VideoDrv_GetRxCount (void); - -/** - \fn VideoDrv_Status_t VideoDrv_GetStatus (void) - \brief Get Video Interface status. - \return \ref VideoDrv_Status_t -*/ -VideoDrv_Status_t VideoDrv_GetStatus (void); - -#ifdef __cplusplus -} -#endif - -#endif /* __VIDEO_DRV_H */ diff --git a/ComputeGraph/cg/nodes/cpp/StreamingSink.h b/ComputeGraph/cg/nodes/cpp/StreamingSink.h deleted file mode 100644 index 00e5dd40..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingSink.h +++ /dev/null @@ -1,80 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: StreamingSink.h - * Description: Streaming Sink working with the RingBuffer - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _STREAMING_SINK_H_ -#define _STREAMING_SINK_H_ - -#include "RingBuffer.h" - -/* This is deprecated. Don't use it */ -template -class StreamingSink: public GenericSink -{ -public: - StreamingSink(FIFOBase &src,ring_config_t *config): - GenericSink(src),mConfig(config){}; - - int prepareForRunning() override - { - if (this->willUnderflow() - ) - { - return(CG_SKIP_EXECUTION_ID_CODE); // Skip execution - } - - return(0); - }; - - int run() override - { - IN *b=this->getReadBuffer(); - - int bufID=ringUserReserveBuffer(mConfig); - uint8_t *buf=ringGetBufferAddress(mConfig,bufID); - - if (buf != NULL) - { - /* If a buffer is available we copy the data to the FIFO - */ - memcpy(buf,(void*)b,inputSize*sizeof(IN)); - - /* We release the buffer so than it can be used by the interrupt */ - ringUserReleaseBuffer(mConfig); - return(0); - } - else - { - return(mConfig->error); - } - - return(0); - } -protected: - ring_config_t *mConfig; -}; - -#endif /* _STREAMING_SINK_H_ */ \ No newline at end of file diff --git a/ComputeGraph/cg/nodes/cpp/StreamingSource.h b/ComputeGraph/cg/nodes/cpp/StreamingSource.h deleted file mode 100644 index 73bb9949..00000000 --- a/ComputeGraph/cg/nodes/cpp/StreamingSource.h +++ /dev/null @@ -1,88 +0,0 @@ -/* ---------------------------------------------------------------------- - * Project: CMSIS DSP Library - * Title: StreamingSource.h - * Description: Streaming source working with the Ring buffer - * - * $Date: 30 July 2021 - * $Revision: V1.10.0 - * - * Target Processor: Cortex-M and Cortex-A cores - * -------------------------------------------------------------------- */ -/* - * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _STREAMING_SOURCE_H_ -#define _STREAMING_SOURCE_H_ - -#include "RingBuffer.h" - -/* This is deprecated. Don't use it */ -template -class StreamingSource: public GenericSource -{ -public: - StreamingSource(FIFOBase &dst,ring_config_t *config): - GenericSource(dst),mConfig(config){}; - - int prepareForRunning() override - { - if (this->willUnderflow() - ) - { - return(CG_SKIP_EXECUTION_ID_CODE); // Skip execution - } - - return(0); - }; - - int run() override - { - OUT *b=this->getWriteBuffer(); - /* - Try to reserve a buffer. If no buffer is available, the task running - this node will sleep. - - If there is a timeout (configured when the ring buffer was initialized) - the function will return a NULL pointer. - - */ - int bufID=ringUserReserveBuffer(mConfig); - uint8_t *buf=ringGetBufferAddress(mConfig,bufID); - - - if (buf != NULL) - { - /* If a buffer is available we copy the data to the FIFO - */ - memcpy((void*)b,buf,outputSize*sizeof(OUT)); - - /* We release the buffer so than it can be used by the interrupt */ - ringUserReleaseBuffer(mConfig); - return(0); - } - else - { - return(mConfig->error); - } - }; - -protected: - ring_config_t *mConfig; - - -}; -#endif /* _STREAMING_SOURCE_H_ */ \ No newline at end of file diff --git a/ComputeGraph/cg/src/GenericNodes.h b/ComputeGraph/cg/src/GenericNodes.h index f73464ba..552d9977 100644 --- a/ComputeGraph/cg/src/GenericNodes.h +++ b/ComputeGraph/cg/src/GenericNodes.h @@ -65,8 +65,9 @@ class FIFOBase{ public: virtual T* getWriteBuffer(int nb)=0; virtual T* getReadBuffer(int nb)=0; - virtual bool willUnderflowWith(int nb)=0; - virtual bool willOverflowWith(int nb)=0; + virtual bool willUnderflowWith(int nb) const = 0; + virtual bool willOverflowWith(int nb) const = 0; + virtual int nbSamplesInFIFO() const = 0; }; @@ -82,8 +83,9 @@ class FIFO: public FIFOBase FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {}; /* Not used in synchronous mode */ - bool willUnderflowWith(int nb) override {return false;}; - bool willOverflowWith(int nb) override {return false;}; + bool willUnderflowWith(int nb) const override {return false;}; + bool willOverflowWith(int nb) const override {return false;}; + int nbSamplesInFIFO() const override {return 0;}; T * getWriteBuffer(int nb) override { @@ -142,8 +144,10 @@ class FIFO: public FIFOBase FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay) {}; FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {}; - bool willUnderflowWith(int nb) override {return false;}; - bool willOverflowWith(int nb) override {return false;}; + /* Not used in synchronous mode */ + bool willUnderflowWith(int nb) const override {return false;}; + bool willOverflowWith(int nb) const override {return false;}; + int nbSamplesInFIFO() const override {return 0;}; T * getWriteBuffer(int nb) override { @@ -226,16 +230,18 @@ class FIFO: public FIFOBase return(ret); } - bool willUnderflowWith(int nb) override + bool willUnderflowWith(int nb) const override { return((nbSamples - nb)<0); } - bool willOverflowWith(int nb) override + bool willOverflowWith(int nb) const override { return((nbSamples + nb)>length); } + int nbSamplesInFIFO() const override {return nbSamples;}; + #ifdef DEBUGSCHED void dump() { diff --git a/ComputeGraph/examples/CMakeLists.txt b/ComputeGraph/examples/CMakeLists.txt index 06f30c0c..bf876a19 100644 --- a/ComputeGraph/examples/CMakeLists.txt +++ b/ComputeGraph/examples/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.15) +cmake_minimum_required (VERSION 3.21) include(CMakePrintHelpers) set(Python_FIND_REGISTRY "LAST") diff --git a/ComputeGraph/examples/example1/generated/scheduler.cpp b/ComputeGraph/examples/example1/generated/scheduler.cpp index 0fcded00..fa8918bd 100644 --- a/ComputeGraph/examples/example1/generated/scheduler.cpp +++ b/ComputeGraph/examples/example1/generated/scheduler.cpp @@ -102,7 +102,8 @@ float32_t buf2[BUFFERSIZE2]={0}; CG_BEFORE_SCHEDULER_FUNCTION -uint32_t scheduler(int *error,int someVariable) +uint32_t scheduler(int *error,const char *testString, + int someVariable) { int cgStaticError=0; uint32_t nbSchedule=0; @@ -119,7 +120,7 @@ uint32_t scheduler(int *error,int someVariable) /* Create node objects */ - ProcessingNode filter(fifo0,fifo1,4,"Test",someVariable); + ProcessingNode filter(fifo0,fifo1,4,testString,someVariable); Sink sink(fifo1); Source source(fifo0); diff --git a/ComputeGraph/examples/example1/generated/scheduler.h b/ComputeGraph/examples/example1/generated/scheduler.h index c1d5cb0d..f595e01f 100644 --- a/ComputeGraph/examples/example1/generated/scheduler.h +++ b/ComputeGraph/examples/example1/generated/scheduler.h @@ -16,7 +16,8 @@ extern "C" #endif -extern uint32_t scheduler(int *error,int someVariable); +extern uint32_t scheduler(int *error,const char *testString, + int someVariable); #ifdef __cplusplus } diff --git a/ComputeGraph/examples/example1/graph.py b/ComputeGraph/examples/example1/graph.py index d4242c0f..e6d33116 100644 --- a/ComputeGraph/examples/example1/graph.py +++ b/ComputeGraph/examples/example1/graph.py @@ -37,8 +37,8 @@ class ProcessingNode(Node): floatType=CType(F32) src=Source("source",floatType,5) b=ProcessingNode("filter",floatType,7,5) -b.addLiteralArg(4,"Test") -b.addVariableArg("someVariable") +b.addLiteralArg(4) +b.addVariableArg("testString","someVariable") sink=Sink("sink",floatType,5) g = Graph() @@ -51,7 +51,9 @@ print("Generate graphviz and code") conf=Configuration() conf.debugLimit=1 -conf.cOptionalArgs="int someVariable" +conf.cOptionalArgs=["const char *testString" + ,"int someVariable" + ] #conf.displayFIFOSizes=True # Prefix for global FIFO buffers #conf.prefix="sched1" diff --git a/ComputeGraph/examples/example1/main.cpp b/ComputeGraph/examples/example1/main.cpp index b0cb113f..8e26aa31 100644 --- a/ComputeGraph/examples/example1/main.cpp +++ b/ComputeGraph/examples/example1/main.cpp @@ -6,6 +6,6 @@ int main(int argc, char const *argv[]) { int error; printf("Start\n"); - uint32_t nbSched=scheduler(&error,1); + uint32_t nbSched=scheduler(&error,"Test",1); return 0; } \ No newline at end of file diff --git a/ComputeGraph/examples/example10/AppNodes.h b/ComputeGraph/examples/example10/AppNodes.h index e588337c..aa3111d8 100644 --- a/ComputeGraph/examples/example10/AppNodes.h +++ b/ComputeGraph/examples/example10/AppNodes.h @@ -31,6 +31,8 @@ #include #include +#include "NullSink.h" + static int count=0; template diff --git a/ComputeGraph/examples/example10/generated/scheduler.cpp b/ComputeGraph/examples/example10/generated/scheduler.cpp index 578a8719..5799c67d 100644 --- a/ComputeGraph/examples/example10/generated/scheduler.cpp +++ b/ComputeGraph/examples/example10/generated/scheduler.cpp @@ -78,9 +78,9 @@ CG_AFTER_INCLUDES Description of the scheduling. */ -static unsigned int schedule[7]= +static unsigned int schedule[9]= { -5,6,2,0,1,3,4, +7,8,2,1,4,0,3,5,6, }; CG_BEFORE_FIFO_BUFFERS @@ -93,8 +93,10 @@ FIFO buffers #define FIFOSIZE1 2 #define FIFOSIZE2 2 #define FIFOSIZE3 2 -#define FIFOSIZE4 2 +#define FIFOSIZE4 3 #define FIFOSIZE5 2 +#define FIFOSIZE6 2 +#define FIFOSIZE7 2 #define BUFFERSIZE1 2 CG_BEFORE_BUFFER @@ -112,7 +114,7 @@ int16_t buf3[BUFFERSIZE3]={0}; CG_BEFORE_BUFFER int16_t buf4[BUFFERSIZE4]={0}; -#define BUFFERSIZE5 2 +#define BUFFERSIZE5 3 CG_BEFORE_BUFFER int16_t buf5[BUFFERSIZE5]={0}; @@ -120,6 +122,14 @@ int16_t buf5[BUFFERSIZE5]={0}; CG_BEFORE_BUFFER int16_t buf6[BUFFERSIZE6]={0}; +#define BUFFERSIZE7 2 +CG_BEFORE_BUFFER +int16_t buf7[BUFFERSIZE7]={0}; + +#define BUFFERSIZE8 2 +CG_BEFORE_BUFFER +int16_t buf8[BUFFERSIZE8]={0}; + CG_BEFORE_SCHEDULER_FUNCTION uint32_t scheduler(int *error) @@ -138,17 +148,21 @@ uint32_t scheduler(int *error) FIFO fifo3(buf4); FIFO fifo4(buf5); FIFO fifo5(buf6); + FIFO fifo6(buf7); + FIFO fifo7(buf8); CG_BEFORE_NODE_INIT; /* Create node objects */ - Duplicate2 dup0(fifo3,fifo4,fifo5); - ProcessingOddEven proc(fifo0,fifo1,fifo2); - SinkAsync sinka(fifo4); - SinkAsync sinkb(fifo5); - SourceEven sourceEven(fifo1); - SourceOdd sourceOdd(fifo0); + NullSink debug(fifo4); + Duplicate2 dup0(fifo2,fifo3,fifo4); + Duplicate2 dup1(fifo5,fifo6,fifo7); + ProcessingOddEven proc(fifo3,fifo0,fifo1); + SinkAsync sinka(fifo6); + SinkAsync sinkb(fifo7); + SourceEven sourceEven(fifo0); + SourceOdd sourceOdd(fifo2); /* Run several schedule iterations */ CG_BEFORE_SCHEDULE; @@ -156,7 +170,7 @@ uint32_t scheduler(int *error) { /* Run a schedule iteration */ CG_BEFORE_ITERATION; - for(unsigned long id=0 ; id < 7; id++) + for(unsigned long id=0 ; id < 9; id++) { CG_BEFORE_NODE_EXECUTION; @@ -167,8 +181,8 @@ uint32_t scheduler(int *error) { bool canRun=true; - canRun &= !fifo2.willUnderflowWith(1); - canRun &= !fifo3.willOverflowWith(1); + canRun &= !fifo1.willUnderflowWith(1); + canRun &= !fifo5.willOverflowWith(1); if (!canRun) { @@ -183,35 +197,47 @@ uint32_t scheduler(int *error) case 1: { - cgStaticError = dup0.prepareForRunning(); + cgStaticError = debug.prepareForRunning(); } break; case 2: { - cgStaticError = proc.prepareForRunning(); + cgStaticError = dup0.prepareForRunning(); } break; case 3: { - cgStaticError = sinka.prepareForRunning(); + cgStaticError = dup1.prepareForRunning(); } break; case 4: { - cgStaticError = sinkb.prepareForRunning(); + cgStaticError = proc.prepareForRunning(); } break; case 5: { - cgStaticError = sourceEven.prepareForRunning(); + cgStaticError = sinka.prepareForRunning(); } break; case 6: + { + cgStaticError = sinkb.prepareForRunning(); + } + break; + + case 7: + { + cgStaticError = sourceEven.prepareForRunning(); + } + break; + + case 8: { cgStaticError = sourceOdd.prepareForRunning(); } @@ -222,7 +248,10 @@ uint32_t scheduler(int *error) } if (cgStaticError == CG_SKIP_EXECUTION_ID_CODE) - continue; + { + cgStaticError = 0; + continue; + } CHECKERROR; @@ -235,8 +264,8 @@ uint32_t scheduler(int *error) int16_t* i0; int16_t* o1; - i0=fifo2.getReadBuffer(1); - o1=fifo3.getWriteBuffer(1); + i0=fifo1.getReadBuffer(1); + o1=fifo5.getWriteBuffer(1); compute(i0,o1,1); cgStaticError = 0; } @@ -245,35 +274,47 @@ uint32_t scheduler(int *error) case 1: { - cgStaticError = dup0.run(); + cgStaticError = debug.run(); } break; case 2: { - cgStaticError = proc.run(); + cgStaticError = dup0.run(); } break; case 3: { - cgStaticError = sinka.run(); + cgStaticError = dup1.run(); } break; case 4: { - cgStaticError = sinkb.run(); + cgStaticError = proc.run(); } break; case 5: { - cgStaticError = sourceEven.run(); + cgStaticError = sinka.run(); } break; case 6: + { + cgStaticError = sinkb.run(); + } + break; + + case 7: + { + cgStaticError = sourceEven.run(); + } + break; + + case 8: { cgStaticError = sourceOdd.run(); } diff --git a/ComputeGraph/examples/example10/graph.py b/ComputeGraph/examples/example10/graph.py index 83371029..550ce59d 100644 --- a/ComputeGraph/examples/example10/graph.py +++ b/ComputeGraph/examples/example10/graph.py @@ -55,6 +55,8 @@ comp=Unary("compute",dataType,1) sinka=SinkAsync("sinka",dataType,1) sinkb=SinkAsync("sinkb",dataType,1) +debug=NullSink("debug",dataType,1) + g = Graph() # Option to customize the default class @@ -67,6 +69,11 @@ g.duplicateNodeClassName = "Duplicate" g.connect(odd.o,proc.ia) g.connect(even.o,proc.ib) +# Just for checking duplicate nodes +# with scaling factor are working. +# In practice, all edge of a duplicate nodes +# should have same FIFO size +g.connect(odd.o,debug.i,fifoScale=3.0) g.connect(proc.o,comp.i) g.connect(comp.o,sinka.i) @@ -95,8 +102,8 @@ conf.asynchronous = True # Increase size of synchronous FIFOs by 100% # for the asynchronous case (so 2 samples # instead of 1 in this example) -conf.FIFOIncrease = 100 # percent - +#conf.FIFOIncrease = 100 # percent +conf.FIFOIncrease = 2.0 #conf.displayFIFOSizes=True # Prefix for global FIFO buffers diff --git a/ComputeGraph/examples/example10/test.dot b/ComputeGraph/examples/example10/test.dot index 490fa64b..208d3b8d 100644 --- a/ComputeGraph/examples/example10/test.dot +++ b/ComputeGraph/examples/example10/test.dot @@ -16,8 +16,17 @@ compute1 [label=< >]; +debug [label=< + + + + +
debug
(NullSink)
>]; + dup0 [shape=point,label=dup0] +dup1 [shape=point,label=dup1] + proc [label=< @@ -64,38 +73,50 @@ sourceOdd [label=< -sourceOdd:i -> proc:ia [label="s16(2)" +sourceEven:i -> proc:ib [label="s16(2)" ,headlabel=<
1
> ,taillabel=<
1
>] -sourceEven:i -> proc:ib [label="s16(2)" +proc:o -> compute1:i [label="s16(2)" ,headlabel=<
1
> ,taillabel=<
1
>] -proc:o -> compute1:i [label="s16(2)" -,headlabel=<
1 -
> +sourceOdd:i -> +dup0 [label="s16(2)" + ,taillabel=<
1
>] + +dup0 -> proc:ia [label="s16(2)" +,headlabel=<
1 +
> +] + + +dup0 -> debug:i [label="s16(3)" +,headlabel=<
1 +
> +] + compute1:i -> -dup0 [label="s16(2)" +dup1 [label="s16(2)" ,taillabel=<
1
>] -dup0 -> sinka:i [label="s16(2)" +dup1 -> sinka:i [label="s16(2)" ,headlabel=<
1
> ] -dup0 -> sinkb:i [label="s16(2)" +dup1 -> sinkb:i [label="s16(2)" ,headlabel=<
1
> ] diff --git a/ComputeGraph/examples/example10/test.pdf b/ComputeGraph/examples/example10/test.pdf index b5508a12..631c0e96 100644 Binary files a/ComputeGraph/examples/example10/test.pdf and b/ComputeGraph/examples/example10/test.pdf differ diff --git a/PythonWrapper/.gitignore b/PythonWrapper/.gitignore index 5e14428f..7766603f 100755 --- a/PythonWrapper/.gitignore +++ b/PythonWrapper/.gitignore @@ -1,4 +1,7 @@ dist/ -build/ examples/rec_2.dat - +build/bin_dsp +build/cmake_install.cmake +build/CMakeFiles +build/Makefile +build/CMakeCache.txt diff --git a/PythonWrapper/CMakeLists.txt b/PythonWrapper/CMakeLists.txt new file mode 100644 index 00000000..4a8eebfe --- /dev/null +++ b/PythonWrapper/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 3.6) + +# Define the project +project (pythonwrapper VERSION 0.1) + + +########### +# +# CMSIS DSP +# + +add_subdirectory(${CMSISDSP}/Source bin_dsp) + diff --git a/PythonWrapper/build/clean.bat b/PythonWrapper/build/clean.bat new file mode 100644 index 00000000..3478faa4 --- /dev/null +++ b/PythonWrapper/build/clean.bat @@ -0,0 +1,5 @@ +DEL /F CMakeCache.txt +RMDIR /S /Q CMakeFiles +DEL /F Makefile +RMDIR /S /Q bin_dsp +DEL /F cmake_install.cmake \ No newline at end of file diff --git a/PythonWrapper/build/create.bat b/PythonWrapper/build/create.bat new file mode 100644 index 00000000..747e861e --- /dev/null +++ b/PythonWrapper/build/create.bat @@ -0,0 +1,8 @@ +cmake -DHOST=YES ^ + -DLOOPUNROLL=ON ^ + -DWRAPPER=YES ^ + -DCMSISDSP="path to CMSIS-DSP folder" ^ + -DCMAKE_C_FLAGS_RELEASE="-std=c11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra" ^ + -DCMAKE_CXX_FLAGS_RELEASE="-fno-rtti -std=c++11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra -Wno-unused-parameter" ^ + -G "Unix Makefiles" .. + diff --git a/PythonWrapper/build_linux/clean.sh b/PythonWrapper/build_linux/clean.sh new file mode 100644 index 00000000..611b023c --- /dev/null +++ b/PythonWrapper/build_linux/clean.sh @@ -0,0 +1,5 @@ +rm -f CMakeCache.txt +rm -rf CMakeFiles +rm -f Makefile +rm -rf bin_dsp +rm -f cmake_install.cmake \ No newline at end of file diff --git a/PythonWrapper/build_linux/create.sh b/PythonWrapper/build_linux/create.sh new file mode 100644 index 00000000..6e271aa3 --- /dev/null +++ b/PythonWrapper/build_linux/create.sh @@ -0,0 +1,11 @@ +cmake -DHOST=YES \ + -DLOOPUNROLL=ON \ + -DWRAPPER=YES \ + -DCMAKE_POSITION_INDEPENDENT_CODE=YES \ + -DCMSISDSP="path to CMSIS-DSP folder" \ + -DCMAKE_C_FLAGS_RELEASE="-std=c11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra" \ + -DCMAKE_CXX_FLAGS_RELEASE="-fno-rtti -std=c++11 -Ofast -ffast-math -DNDEBUG -Wall -Wextra -Wno-unused-parameter" \ + -G "Unix Makefiles" .. + +# For Mac universal lib +# -arch x86_64 -arch arm64 -mmacosx-version-min=11.0 \ No newline at end of file diff --git a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_transform.c b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_transform.c index b2798c5f..9abd36e9 100755 --- a/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_transform.c +++ b/PythonWrapper/cmsisdsp_pkg/src/cmsisdsp_transform.c @@ -2291,11 +2291,11 @@ cmsis_arm_rfft_q15(PyObject *obj, PyObject *args) inputSize=selfS->instance->fftLenReal; if (selfS->instance->ifftFlagR) { - outputSize = inputSize-2; + outputSize = inputSize; } else { - outputSize = 2*inputSize+2; + outputSize = 2*inputSize; } GETARGUMENT(pSrc,NPY_INT16,int16_t,int16_t); @@ -2365,11 +2365,11 @@ cmsis_arm_rfft_q31(PyObject *obj, PyObject *args) inputSize=selfS->instance->fftLenReal; if (selfS->instance->ifftFlagR) { - outputSize = inputSize-2; + outputSize = inputSize; } else { - outputSize = 2*inputSize+2; + outputSize = 2*inputSize; } GETARGUMENT(pSrc,NPY_INT32,int32_t,int32_t); diff --git a/PythonWrapper/examples/debug.py b/PythonWrapper/examples/debug.py index 59b93754..7e6b483b 100755 --- a/PythonWrapper/examples/debug.py +++ b/PythonWrapper/examples/debug.py @@ -1,20 +1,81 @@ import cmsisdsp as dsp +import cmsisdsp.fixedpoint as f + import numpy as np from scipy import signal +import matplotlib.pyplot as plt +import scipy.fft + +import colorama +from colorama import init,Fore, Back, Style +from numpy.testing import assert_allclose + +init() + +def printTitle(s): + print("\n" + Fore.GREEN + Style.BRIGHT + s + Style.RESET_ALL) + +def printSubTitle(s): + print("\n" + Style.BRIGHT + s + Style.RESET_ALL) + + +def chop(A, eps = 1e-6): + B = np.copy(A) + B[np.abs(A) < eps] = 0 + return B + +nb = 32 +signal = np.cos(2 * np.pi * np.arange(nb) / nb)*np.cos(0.2*2 * np.pi * np.arange(nb) / nb) + +ref=scipy.fft.rfft(signal) +invref = scipy.fft.irfft(ref) + +print(f"ref length = {len(ref)}") +print(ref) + +# Convert ref to CMSIS-DSP format +referenceFloat=np.zeros(2*len(ref)) +print(f"referenceFloat length = {len(referenceFloat)}") +# Replace complex datatype by real datatype +referenceFloat[0::2] = np.real(ref) +referenceFloat[1::2] = np.imag(ref) +# Copy Nyquist frequency value into first +# sample.This is just a storage trick so that the +# output of the RFFT has same length as input +# It is legacy behavior that we need to keep +# for backward compatibility but it is not +# very pretty +#referenceFloat[1] = np.real(ref[-1]) + +rifftQ31=dsp.arm_rfft_instance_q31() +status=dsp.arm_rfft_init_q31(rifftQ31,nb,1,1) +# Apply CMSIS-DSP scaling +referenceQ31 = f.toQ31(referenceFloat / nb) + +resultQ31 = dsp.arm_rfft_q31(rifftQ31,referenceQ31) +resultF = f.Q31toF32(resultQ31) + +print(f"resultF length = {len(resultF)}") +assert_allclose(invref/nb,resultF,atol=1e-6) + +signalQ31 = f.toQ31(signal) +rfftQ31=dsp.arm_rfft_instance_q31() +status=dsp.arm_rfft_init_q31(rfftQ31,nb,0,1) +resultQ31 = dsp.arm_rfft_q31(rfftQ31,signalQ31) +print(len(resultQ31)) +print(2*nb) +resultF = f.Q31toF32(resultQ31) * nb -firf32 = dsp.arm_fir_instance_f32() -dsp.arm_fir_init_f32(firf32,3,[1.,2,3],[0,0,0,0,0,0,0]) -print(firf32.numTaps()) -filtered_x = signal.lfilter([3,2,1.], 1.0, [1,2,3,4,5,1,2,3,4,5]) -print(filtered_x) -print(dsp.arm_fir_f32(firf32,[1,2,3,4,5])) -print(dsp.arm_fir_f32(firf32,[1,2,3,4,5])) +def compareWithConjugatePart(r): + res = r[0::2] + 1j * r[1::2] + conjPart = res[nb:nb//2:-1].conj() + refPart = res[1:nb//2] + assert(np.equal(refPart , conjPart).all()) -a=np.array([[1.,2,3,4],[5,6,7,8],[9,10,11,12]]) -b=np.array([[1.,2,3,4],[5.1,6,7,8],[9.1,10,11,12]]) -#print(a+b) +compareWithConjugatePart(resultF) -#print("OK") +res = resultF[0::2] + 1j * resultF[1::2] +print(res) -v=dsp.arm_mat_add_f32(a,b) -print(v) +print(res[0:nb//2+1]) +print(res[0:nb//2+1].shape) \ No newline at end of file diff --git a/PythonWrapper/examples/example_1_10.py b/PythonWrapper/examples/example_1_10.py index c2462151..1e132da4 100644 --- a/PythonWrapper/examples/example_1_10.py +++ b/PythonWrapper/examples/example_1_10.py @@ -6,7 +6,7 @@ import math import colorama from colorama import init,Fore, Back, Style from numpy.testing import assert_allclose -import matplotlib.pyplot as plt +#import matplotlib.pyplot as plt from scipy import signal import scipy.signal.windows as win diff --git a/PythonWrapper/examples/example_1_9.py b/PythonWrapper/examples/example_1_9.py index 5d211ce4..9654e199 100644 --- a/PythonWrapper/examples/example_1_9.py +++ b/PythonWrapper/examples/example_1_9.py @@ -6,7 +6,7 @@ import math import colorama from colorama import init,Fore, Back, Style from numpy.testing import assert_allclose -import matplotlib.pyplot as plt +#import matplotlib.pyplot as plt from scipy import signal init() diff --git a/PythonWrapper/examples/testrfft_all.py b/PythonWrapper/examples/testrfft_all.py index 0e2597b3..0636c34d 100644 --- a/PythonWrapper/examples/testrfft_all.py +++ b/PythonWrapper/examples/testrfft_all.py @@ -3,7 +3,7 @@ import cmsisdsp.fixedpoint as f import numpy as np from scipy import signal -import matplotlib.pyplot as plt +#import matplotlib.pyplot as plt import scipy.fft import colorama @@ -24,12 +24,42 @@ def chop(A, eps = 1e-6): B[np.abs(A) < eps] = 0 return B +# For fixed point version, compare that +# the conjugate part is really the conjugate part +def compareWithConjugatePart(r): + res = r[0::2] + 1j * r[1::2] + conjPart = res[nb:nb//2:-1].conj() + refPart = res[1:nb//2] + assert(np.equal(refPart , conjPart).all()) + nb = 32 signal = np.cos(2 * np.pi * np.arange(nb) / nb)*np.cos(0.2*2 * np.pi * np.arange(nb) / nb) ref=scipy.fft.rfft(signal) invref = scipy.fft.irfft(ref) +assert(len(ref) == (nb // 2) + 1) +assert(len(invref) == nb) + +# Length of arrays for the float implementation +# of the RFFT (in float so there is a factor 2 +# when the samples are complex) + +RFFT_F_IN_LENGTH = nb # real +RFFT_F_OUT_LENGTH = nb # complex (so nb // 2 complex) + +RIFFT_F_IN_LENGTH = nb # complex +RIFFT_F_OUT_LENGTH = nb # real + +# Length of arrays for the fixed point implementation +# of the RFFT +RFFT_Q_IN_LENGTH = nb +RFFT_Q_OUT_LENGTH = 2*nb + +# Conjugate part ignored +RIFFT_Q_IN_LENGTH = nb + 2 +RIFFT_Q_OUT_LENGTH = nb + # Convert ref to CMSIS-DSP format referenceFloat=np.zeros(nb) # Replace complex datatype by real datatype @@ -43,6 +73,10 @@ referenceFloat[1::2] = np.imag(ref)[:-1] # very pretty referenceFloat[1] = np.real(ref[-1]) +referenceFixed=np.zeros(2*len(ref)) +referenceFixed[0::2] = np.real(ref) +referenceFixed[1::2] = np.imag(ref) + printTitle("RFFT FAST F64") printSubTitle("RFFT") @@ -51,7 +85,8 @@ printSubTitle("RFFT") rfftf64=dsp.arm_rfft_fast_instance_f64() status=dsp.arm_rfft_fast_init_f64(rfftf64,nb) result = dsp.arm_rfft_fast_f64(rfftf64,signal,0) - +assert(len(signal) == RFFT_F_IN_LENGTH) +assert(len(result) == RFFT_F_OUT_LENGTH) assert_allclose(referenceFloat,result) @@ -60,6 +95,8 @@ printSubTitle("RIFFT") rifftf64=dsp.arm_rfft_fast_instance_f64() status=dsp.arm_rfft_fast_init_f64(rifftf64,nb) result = dsp.arm_rfft_fast_f64(rifftf64,referenceFloat,1) +assert(len(referenceFloat) == RIFFT_F_IN_LENGTH) +assert(len(result) == RIFFT_F_OUT_LENGTH) assert_allclose(invref,result,atol=1e-15) @@ -71,6 +108,8 @@ printSubTitle("RFFT") rfftf32=dsp.arm_rfft_fast_instance_f32() status=dsp.arm_rfft_fast_init_f32(rfftf32,nb) result = dsp.arm_rfft_fast_f32(rfftf32,signal,0) +assert(len(signal) == RFFT_F_IN_LENGTH) +assert(len(result) == RFFT_F_OUT_LENGTH) assert_allclose(referenceFloat,result,rtol=3e-6) @@ -80,17 +119,12 @@ printSubTitle("RIFFT") rifftf32=dsp.arm_rfft_fast_instance_f32() status=dsp.arm_rfft_fast_init_f32(rifftf32,nb) result = dsp.arm_rfft_fast_f32(rifftf32,referenceFloat,1) +assert(len(referenceFloat) == RIFFT_F_IN_LENGTH) +assert(len(result) == RIFFT_F_OUT_LENGTH) assert_allclose(invref,result,atol=1e-7) # Fixed point -# Reference from fixed point arithmetric. -# The RFFT are not packing the Nyquist frequency -# real value in sample 0 -referenceFloat=np.zeros(nb+2) -# Replace complex datatype by real datatype -referenceFloat[0::2] = np.real(ref) -referenceFloat[1::2] = np.imag(ref) printTitle("RFFT Q31") @@ -100,11 +134,17 @@ signalQ31 = f.toQ31(signal) rfftQ31=dsp.arm_rfft_instance_q31() status=dsp.arm_rfft_init_q31(rfftQ31,nb,0,1) resultQ31 = dsp.arm_rfft_q31(rfftQ31,signalQ31) +assert(len(signalQ31) == RFFT_Q_IN_LENGTH) +assert(len(resultQ31) == RFFT_Q_OUT_LENGTH) +compareWithConjugatePart(resultQ31) + # Drop the conjugate part which is not computed by scipy resultQ31 = resultQ31[:nb+2] +assert(len(resultQ31) == RIFFT_Q_IN_LENGTH) + resultF = f.Q31toF32(resultQ31) * nb -assert_allclose(referenceFloat,resultF,rtol=1e-6,atol=1e-6) +assert_allclose(referenceFixed,resultF,rtol=1e-6,atol=1e-6) printSubTitle("RIFFT") @@ -112,11 +152,13 @@ printSubTitle("RIFFT") rifftQ31=dsp.arm_rfft_instance_q31() status=dsp.arm_rfft_init_q31(rifftQ31,nb,1,1) # Apply CMSIS-DSP scaling -referenceQ31 = f.toQ31(referenceFloat / nb) -resultQ31 = dsp.arm_rfft_q31(rifftQ31,referenceFloat) +referenceQ31 = f.toQ31(referenceFixed/ nb) +resultQ31 = dsp.arm_rfft_q31(rifftQ31,referenceQ31) resultF = f.Q31toF32(resultQ31) +assert(len(referenceQ31) == RIFFT_Q_IN_LENGTH) +assert(len(resultQ31) == RIFFT_Q_OUT_LENGTH) -assert_allclose(invref,result,atol=1e-6) +assert_allclose(invref/nb,resultF,atol=1e-6) printTitle("RFFT Q15") @@ -126,11 +168,17 @@ signalQ15 = f.toQ15(signal) rfftQ15=dsp.arm_rfft_instance_q15() status=dsp.arm_rfft_init_q15(rfftQ15,nb,0,1) resultQ15 = dsp.arm_rfft_q15(rfftQ15,signalQ15) +assert(len(signalQ15) == RFFT_Q_IN_LENGTH) +assert(len(resultQ15) == RFFT_Q_OUT_LENGTH) +compareWithConjugatePart(resultQ15) + # Drop the conjugate part which is not computed by scipy resultQ15 = resultQ15[:nb+2] +assert(len(resultQ15) == RIFFT_Q_IN_LENGTH) + resultF = f.Q15toF32(resultQ15) * nb -assert_allclose(referenceFloat,resultF,rtol=1e-6,atol=1e-2) +assert_allclose(referenceFixed,resultF,rtol=1e-6,atol=1e-2) printSubTitle("RIFFT") @@ -138,9 +186,11 @@ printSubTitle("RIFFT") rifftQ15=dsp.arm_rfft_instance_q15() status=dsp.arm_rfft_init_q15(rifftQ15,nb,1,1) # Apply CMSIS-DSP scaling -referenceQ15 = f.toQ15(referenceFloat / nb) -resultQ15 = dsp.arm_rfft_q15(rifftQ15,referenceFloat) +referenceQ15 = f.toQ15(referenceFixed / nb) +resultQ15 = dsp.arm_rfft_q15(rifftQ15,referenceQ15) resultF = f.Q15toF32(resultQ15) +assert(len(referenceQ15) == RIFFT_Q_IN_LENGTH) +assert(len(resultQ15) == RIFFT_Q_OUT_LENGTH) -assert_allclose(invref,result,atol=1e-2) +assert_allclose(invref/nb,resultF,atol=1e-3) diff --git a/PythonWrapper_README.md b/PythonWrapper_README.md index 9e7fefce..fc960a39 100644 --- a/PythonWrapper_README.md +++ b/PythonWrapper_README.md @@ -61,13 +61,16 @@ Since the [CMSIS-DSP](https://github.com/ARM-software/CMSIS-DSP) wrapper is usin > pip install numpy Once `NumPy` is installed, you can build the [CMSIS-DSP](https://github.com/ARM-software/CMSIS-DSP) python wrapper. Go to folder `CMSIS/DSP`. -(In a previous version you had to go to the `PythonWrapper` folder. Now the `setup.py` is inside the DSP folder). Now, you can install the cmsisdsp package in editable mode: - > pip install -e "Path To The Folder Containing setup.py" + > pip install -e . +Before using this command, you need to rebuild the CMSIS-DSP library which is no more built by the `setup.py` script. +There is a `CMakeLists.txt` in the `PythonWrapper` folder for this. The `build` folders in `PythonWrapper` are giving some examples of the options to use with the `cmake` command to generate the `Makefile` and build the library. + +This library is then used by the `setup.py` script to build the Python extension. ## Running the examples @@ -239,6 +242,12 @@ The wrapper is now containing the compute graph Python scripts and you should re # Change history +## Version 1.9.6: + +* Corrections to the RFFTs APIs +* More flexibility in the compute graph to specify the additional arguments of the scheduler and nodes +* Possibility to set the FIFO scaling factor at FIFO level (in asynchronous mode) + ## Version 1.9.5: Same as 1.9.4 but will work in Google Colab. diff --git a/README.md b/README.md index f962b8c9..2e2c69dc 100755 --- a/README.md +++ b/README.md @@ -55,9 +55,7 @@ The Python scripts for the static scheduler generator are part of the CMSIS-DSP The header files are part of the CMSIS-DSP pack (version 1.10.2 and above). -The audio streaming nodes on top of CMSIS-RTOS2 are not part of the CMSIS-DSP pack but can be found in the repository. They are demo quality only. They can only be used with Arm Virtual Hardware. - -The Compute Graph is making it easier to implement a streaming solution : connecting different compute kernels each consuming and producing different amount of data. +he Compute Graph is making it easier to implement a streaming solution : connecting different compute kernels each consuming and producing different amount of data. ## Support / Contact @@ -222,6 +220,44 @@ The final executable has no extension in the filename. Of course, on your fast model or virtual hardware you should use the right configuration file (to enable float, to enable FVP, to enable semihosting if needed for the examples ...) +## Code size + +The linker may be able, in some cases, to remove the unused tables (like FFT tables) but: + +* It is not a robust solution because it is dependent on how the code is written and the linker is not always able to deduce that some tables are not used +* It often leads to a coding style where implementation details are visible for the initializations (to help the linker). It thus makes it more difficult to move between different architectures +* It often relies on toolchain features which are embedded related but CMSIS-DSP is also used on very high end system where those features may be missing + +For all those reasons, compilation options have been introduced to control what's included in the library build. Those options are providing a more complex but more robust and portable solution. + +If no new option is defined, everything will behave as usual and as consequence all tables will be included in the build. There are lot of FFT tables and some are big (F64, 4096 samples for instance). + +If `ARM_DSP_CONFIG_TABLES` is defined then the new compilation options will be taken into account. + +It is strongly suggested to use the new Python script `cmsisdspconfig.py` to generate the `-D` options to use on the compiler command line. + + pip install streamlit + streamlit run cmsisdspconfig.py + +If you use `cmake`, it is also easy since high level options are defined and they will select the right compilation options. + +For instance, if you want to use the `arm_rfft_fast_f32` for a 32 sample RFFT, in` fft.cmake` you'll see an option `RFFT_FAST_F32_32`. + +If you don't use cmake nor the Python script, you can just look at `fft.cmake` or `interpol.cmake` in `Source` to see which compilation options are needed. + +We see, that the following symbols need to be enabled for `RFFT_FAST_F32_32` with 32 samples: + +* `ARM_TABLE_TWIDDLECOEF_F32_16 ` +* `ARM_TABLE_BITREVIDX_FLT_16` +* `ARM_TABLE_TWIDDLECOEF_RFFT_F32_32` +* `ARM_TABLE_TWIDDLECOEF_F32_16` + +In addition to that, `ARM_FFT_ALLOW_TABLES` must also be defined. + +This last symbol is required because if no transform functions are included in the build, then by default all flags related to FFT tables are ignored. + + + ## Folders and files The only folders required to build and use CMSIS-DSP Library are: @@ -280,32 +316,3 @@ And we have a script to make it easier to customize the build: * cmsisdspconfig.py: * Web browser UI to generate build configurations (temporary until the CMSIS-DSP configuration is reworked to be simpler and more maintainable) - -## Compilation symbols for tables - -Some new compilations symbols have been introduced to avoid including all the tables if they are not needed. - -If no new symbol is defined, everything will behave as usual. If `ARM_DSP_CONFIG_TABLES` is defined then the new symbols will be taken into account. - -It is strongly suggested to use the new Python script `cmsisdspconfig.py` to generate the -D options to use on the compiler command line. - - pip install streamlit - streamlit run cmsisdspconfig.py - -If you use `cmake`, it is also easy since high level options are defined and they will select the right compilation symbols. - -For instance, if you want to use the `arm_rfft_fast_f32`, in` fft.cmake` you'll see an option `RFFT_FAST_F32_32`. - -If you don't use cmake nor the Python script, you can just look at `fft.cmake` or `interpol.cmake` in `Source` to see which compilation symbols are needed. - -We see, for `arm_rfft_fast_f32`, that the following symbols need to be enabled : - -* `ARM_TABLE_TWIDDLECOEF_F32_16 ` -* `ARM_TABLE_BITREVIDX_FLT_16` -* `ARM_TABLE_TWIDDLECOEF_RFFT_F32_32` -* `ARM_TABLE_TWIDDLECOEF_F32_16` - -In addition to that, `ARM_DSP_CONFIG_TABLES` must be enabled and finally `ARM_FFT_ALLOW_TABLES` must also be defined. - -This last symbol is required because if no transform functions are included in the build, then by default all flags related to FFT tables are ignored. - diff --git a/Scripts/git/gen_pack.sh b/Scripts/git/gen_pack.sh index 30477ec3..39dc652b 100644 --- a/Scripts/git/gen_pack.sh +++ b/Scripts/git/gen_pack.sh @@ -119,8 +119,6 @@ PACK_BASE_FILES=" ComputeGraph/cg/nodes/cpp/NullSink.h ComputeGraph/cg/nodes/cpp/OverlapAndAdd.h ComputeGraph/cg/nodes/cpp/SlidingBuffer.h - ComputeGraph/cg/nodes/cpp/StreamingSink.h - ComputeGraph/cg/nodes/cpp/StreamingSource.h ComputeGraph/cg/nodes/cpp/ToComplex.h ComputeGraph/cg/nodes/cpp/ToReal.h ComputeGraph/cg/nodes/cpp/Unzip.h diff --git a/Source/TransformFunctions/arm_rfft_f32.c b/Source/TransformFunctions/arm_rfft_f32.c index 8844b73a..8a7e11e7 100644 --- a/Source/TransformFunctions/arm_rfft_f32.c +++ b/Source/TransformFunctions/arm_rfft_f32.c @@ -86,12 +86,6 @@ void arm_split_rifft_f32( @param[out] pDst points to the output buffer @return none - @par - For the RIFFT, the source buffer must at least have length - fftLenReal + 2. - The last two elements must be equal to what would be generated - by the RFFT: - (pSrc[0] - pSrc[1]) and 0.0f */ void arm_rfft_f32( diff --git a/Source/TransformFunctions/arm_rfft_fast_f32.c b/Source/TransformFunctions/arm_rfft_fast_f32.c index 3e94d5b4..4d76c0d0 100644 --- a/Source/TransformFunctions/arm_rfft_fast_f32.c +++ b/Source/TransformFunctions/arm_rfft_fast_f32.c @@ -479,9 +479,8 @@ void merge_rfft_f32( @par The real sequence is initially treated as if it were complex to perform a CFFT. Later, a processing stage reshapes the data to obtain half of the frequency spectrum - in complex format. Except the first complex number that contains the two real numbers - X[0] and X[N/2] all the data is complex. In other words, the first complex sample - contains two real values packed. + in complex format. + @par The input for the inverse RFFT should keep the same format as the output of the forward RFFT. A first processing stage pre-process the data to later perform an @@ -500,16 +499,21 @@ void merge_rfft_f32( @par The FFT of a real N-point sequence has even symmetry in the frequency domain. The second half of the data equals the conjugate of the first half flipped in frequency. - Looking at the data, we see that we can uniquely represent the FFT using only N/2 complex numbers. - These are packed into the output array in alternating real and imaginary components: + This conjugate part is not computed by the float RFFT. As consequence, the output of + a N point real FFT should be a N//2 + 1 complex numbers so N + 2 floats. + @par + It happens that the first complex of number of the RFFT output is actually + all real. Its real part represents the DC offset. + The value at Nyquist frequency is also real. + @par - X = { real[0], imag[0], real[1], imag[1], real[2], imag[2] ... - real[(N/2)-1], imag[(N/2)-1 } + Those two complex numbers can be encoded with 2 floats rather than using two numbers + with an imaginary part set to zero. @par - It happens that the first complex number (real[0], imag[0]) is actually - all real. real[0] represents the DC offset, and imag[0] should be 0. - (real[1], imag[1]) is the fundamental frequency, (real[2], imag[2]) is - the first harmonic and so on. + The implementation is using a trick so that the output buffer can be N float : + the last real is packaged in the imaginary part of the first complex (since + this imaginary part is not used and is zero). + @par The real FFT functions pack the frequency domain data in this fashion. The forward transform outputs the data in this form and the inverse @@ -519,7 +523,16 @@ void merge_rfft_f32( samples. @par Q15 and Q31 The real algorithms are defined in a similar manner and utilize N/2 complex - transforms behind the scenes. + transforms behind the scenes. + + @par + But warning, contrary to the float version, the fixed point implementation + RFFT is also computing the conjugate part (except for MVE version) so the + output buffer must be bigger. + Also the fixed point RFFTs are not using any trick to pack the DC and Nyquist + frequency in the same complex number. + The RIFFT is not using the conjugate part but it is still using the Nyquist + frequency value. The details are given in the documentation for the functions. @par The complex transforms used internally include scaling to prevent fixed-point overflows. The overall scaling equals 1/(fftLen/2). diff --git a/Source/TransformFunctions/arm_rfft_q15.c b/Source/TransformFunctions/arm_rfft_q15.c index 33d94ac1..a0fc57eb 100644 --- a/Source/TransformFunctions/arm_rfft_q15.c +++ b/Source/TransformFunctions/arm_rfft_q15.c @@ -93,15 +93,13 @@ void arm_split_rifft_q15( | 8192 | 1.15 | 13.3 | 0 | @par - If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + 2 - since it is containing the conjugate part. (N/2 + 1 + N/2 complex samples) + If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + since it is containing the conjugate part (except for MVE version where N+2 is enough). The input buffer is modified by this function. @par - For the RIFFT, the source buffer must have at least length - fftLenReal + 2 which is (N/2 + 1 complex samples). It is not using the conjugate part. - The last two elements must be equal to what would be generated - by the RFFT: - (pSrc[0] - pSrc[1]) >> 1 and 0 + For the RIFFT, the source buffer must have length N+2 since the Nyquist frequency value + is needed but conjugate part is ignored. + It is not using the packing trick of the float version. */ void arm_rfft_q15( diff --git a/Source/TransformFunctions/arm_rfft_q31.c b/Source/TransformFunctions/arm_rfft_q31.c index 0f325a9c..ba5e5798 100644 --- a/Source/TransformFunctions/arm_rfft_q31.c +++ b/Source/TransformFunctions/arm_rfft_q31.c @@ -93,16 +93,14 @@ void arm_split_rifft_q31( | 8192 | 1.31 | 13.19 | 0 | @par - If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + 2 - since it is containing the conjugate part. (N/2 + 1 + N/2 complex samples) + If the input buffer is of length N (fftLenReal), the output buffer must have length 2N + since it is containing the conjugate part (except for MVE version where N+2 is enough). The input buffer is modified by this function. @par - For the RIFFT, the source buffer must have at least length - fftLenReal + 2 which is (N/2 + 1 complex samples). It is not using the conjugate part. - The last two elements must be equal to what would be generated - by the RFFT: - (pSrc[0] - pSrc[1]) >> 1 and 0 - + For the RIFFT, the source buffer must have length N+2 since the Nyquist frequency value + is needed but conjugate part is ignored. + It is not using the packing trick of the float version. + */ void arm_rfft_q31( diff --git a/cmsisdsp/cg/scheduler/ccode.py b/cmsisdsp/cg/scheduler/ccode.py index 00cccfce..e0c42be1 100644 --- a/cmsisdsp/cg/scheduler/ccode.py +++ b/cmsisdsp/cg/scheduler/ccode.py @@ -41,6 +41,10 @@ def gencode(sched,directory,config): schedDescription="" + if isinstance(config.cOptionalArgs,list): + spc = " " * 30 + config.cOptionalArgs = f",\n{spc}".join(config.cOptionalArgs) + # Asychronous implies code array and switchCase if config.asynchronous: config.codeArray = True diff --git a/cmsisdsp/cg/scheduler/description.py b/cmsisdsp/cg/scheduler/description.py index 2f81515e..24cd3a25 100644 --- a/cmsisdsp/cg/scheduler/description.py +++ b/cmsisdsp/cg/scheduler/description.py @@ -74,7 +74,7 @@ class FifoBuffer: class FIFODesc: """A FIFO connecting two nodes""" - def __init__(self,fifoid,fifoClass): + def __init__(self,fifoid,fifoClass,fifoScale): # The FIFO is in fact just an array self.isArray=False # FIFO length @@ -93,6 +93,7 @@ class FIFODesc: # FIFO delay self.delay=0 self.fifoClass = fifoClass + self.fifoScale = fifoScale # Used for liveliness analysis # To share buffers between FIFO in memory optimization @@ -173,6 +174,9 @@ class Graph(): self._allFIFOs = None self._allBuffers = None self._FIFOClasses = {} + # In async mode, scaling factor for a given + # FIFO to override the global scaling factor + self._FIFOScale = {} # Topological sorting of nodes # computed during topology matrix # and used for some scheduling @@ -224,9 +228,17 @@ class Graph(): def connectDup(self,destination,outputIO,theId): if (destination[theId][1]!=0): - self.connectWithDelay(outputIO,destination[theId][0],destination[theId][1],dupAllowed=False,fifoClass=destination[theId][2]) + self.connectWithDelay(outputIO,destination[theId][0], + destination[theId][1], + dupAllowed=False, + fifoClass=destination[theId][2], + fifoScale=destination[theId][3]) else: - self.connect(outputIO,destination[theId][0],dupAllowed=False,fifoClass=destination[theId][2]) + self.connect(outputIO,destination[theId][0], + dupAllowed=False, + fifoClass=destination[theId][2], + fifoScale=destination[theId][3] + ) @@ -289,6 +301,7 @@ class Graph(): destinations = [] delays = [] + self._sortedNodes = None self._sortedEdges = None for f in fifo: @@ -299,16 +312,19 @@ class Graph(): nodeb = f[1] fifoClass = self.defaultFIFOClass + fifoScale = 1.0 if (nodea,nodeb) in self._FIFOClasses: fifoClass = self._FIFOClasses[(nodea,nodeb)] - + if (nodea,nodeb) in self._FIFOScale: + fifoScale = self._FIFOScale[(nodea,nodeb)] + if (nodea,nodeb) in self._delays: delay = self._delays[(nodea,nodeb)] else: delay = 0 - destinations.append((nodeb,delay,fifoClass)) + destinations.append((nodeb,delay,fifoClass,fifoScale)) nodea.fifo=None nodeb.fifo=None @@ -327,6 +343,8 @@ class Graph(): del self._edges[(nodea,nodeb)] if (nodea,nodeb) in self._FIFOClasses: del self._FIFOClasses[(nodea,nodeb)] + if (nodea,nodeb) in self._FIFOScale: + del self._FIFOScale[(nodea,nodeb)] if (nodea,nodeb) in self._delays: del self._delays[(nodea,nodeb)] @@ -351,7 +369,7 @@ class Graph(): - def connect(self,nodea,nodeb,dupAllowed=True,fifoClass=None): + def connect(self,nodea,nodeb,dupAllowed=True,fifoClass=None,fifoScale = 1.0): if fifoClass is None: fifoClass = self.defaultFIFOClass # When connecting to a constant node we do nothing @@ -374,6 +392,7 @@ class Graph(): nodeb.fifo=(nodea,nodeb) self._edges[(nodea,nodeb)]=True self._FIFOClasses[(nodea,nodeb)] = fifoClass + self._FIFOScale[(nodea,nodeb)] = fifoScale if not (nodea.owner in self._nodes): self._nodes[nodea.owner]=True if not (nodeb.owner in self._nodes): @@ -381,14 +400,14 @@ class Graph(): else: raise IncompatibleIO - def connectWithDelay(self,nodea,nodeb,delay,dupAllowed=True,fifoClass=None): + def connectWithDelay(self,nodea,nodeb,delay,dupAllowed=True,fifoClass=None,fifoScale=1.0): if fifoClass is None: fifoClass = self.defaultFIFOClass # We cannot connect with delay to a constant node if (isinstance(nodea,Constant)): raise CannotDelayConstantError else: - self.connect(nodea,nodeb,dupAllowed=dupAllowed,fifoClass=fifoClass) + self.connect(nodea,nodeb,dupAllowed=dupAllowed,fifoClass=fifoClass,fifoScale = fifoScale) self._delays[(nodea,nodeb)] = delay def __str__(self): @@ -406,7 +425,19 @@ class Graph(): for fifo in allFIFOs: edge = self._sortedEdges[fifo.fifoID] if config.asynchronous: - fifo.length = int(math.ceil(fifoLengths[fifo.fifoID] * (1.0 + 1.0*config.FIFOIncrease/100))) + if edge in self._FIFOScale: + fifoScale = self._FIFOScale[edge] + fifo.fifoScale = fifoScale + + if fifoScale != 1.0: + scale = fifoScale + else: + scale = 1.0 + if type(config.FIFOIncrease) == float: + scale = config.FIFOIncrease + else: + scale = (1.0 + 1.0*config.FIFOIncrease/100) + fifo.length = int(math.ceil(fifoLengths[fifo.fifoID] * scale)) else: fifo.length = fifoLengths[fifo.fifoID] src,dst = edge @@ -866,7 +897,7 @@ class Graph(): nbFIFOS = t.shape[0] allFIFOs = [] for i in range(nbFIFOS): - allFIFOs.append(FIFODesc(i,self.defaultFIFOClass)) + allFIFOs.append(FIFODesc(i,self.defaultFIFOClass,1.0)) # Normalization vector # For static scheduling it is diff --git a/cmsisdsp/cg/scheduler/node.py b/cmsisdsp/cg/scheduler/node.py index 97909947..117a08e0 100644 --- a/cmsisdsp/cg/scheduler/node.py +++ b/cmsisdsp/cg/scheduler/node.py @@ -302,19 +302,34 @@ class BaseNode: else: return(0) + def _addLiteralItem(self,item): + if self.schedArgs: + self.schedArgs.append(ArgLiteral(item)) + else: + self.schedArgs=[ArgLiteral(item)] + def addLiteralArg(self,*ls): for l in ls: - if self.schedArgs: - self.schedArgs.append(ArgLiteral(l)) + if isinstance(l, list): + for i in l: + self._addLiteralItem(i) else: - self.schedArgs=[ArgLiteral(l)] + self._addLiteralItem(l) + + def _addVariableItem(self,item): + if self.schedArgs: + self.schedArgs.append(VarLiteral(item)) + else: + self.schedArgs=[VarLiteral(item)] def addVariableArg(self,*ls): for l in ls: - if self.schedArgs: - self.schedArgs.append(VarLiteral(l)) + if isinstance(l, list): + for i in l: + self._addVariableItem(i) else: - self.schedArgs=[VarLiteral(l)] + self._addVariableItem(l) + @property def isConstantNode(self): diff --git a/cmsisdsp/version.py b/cmsisdsp/version.py index d5ecdc81..84b6fca7 100755 --- a/cmsisdsp/version.py +++ b/cmsisdsp/version.py @@ -1,2 +1,2 @@ # Python wrapper version -__version__ = "1.9.5" +__version__ = "1.9.6" diff --git a/setup.py b/setup.py index 988bee54..a0748d73 100644 --- a/setup.py +++ b/setup.py @@ -21,135 +21,24 @@ if sys.platform == 'win32': else: cflags = ["-Wno-attributes","-Wno-unused-function","-Wno-unused-variable","-Wno-implicit-function-declaration","-DCMSISDSP","-D__GNUC_PYTHON__"] -transform = glob.glob(os.path.join(ROOT,"Source","TransformFunctions","*.c")) - -# Files are present when creating the source distribution -# but they are not copied to the source distribution -# When doing pip install those files are not prevent -# and it should not fail -try: - transform.remove(os.path.join(ROOT,"Source","TransformFunctions","TransformFunctions.c")) - transform.remove(os.path.join(ROOT,"Source","TransformFunctions","TransformFunctionsF16.c")) -except: - pass - -support = glob.glob(os.path.join(ROOT,"Source","SupportFunctions","*.c")) - -try: - support.remove(os.path.join(ROOT,"Source","SupportFunctions","SupportFunctions.c")) - support.remove(os.path.join(ROOT,"Source","SupportFunctions","SupportFunctionsF16.c")) -except: - pass - -fastmath = glob.glob(os.path.join(ROOT,"Source","FastMathFunctions","*.c")) -try: - fastmath.remove(os.path.join(ROOT,"Source","FastMathFunctions","FastMathFunctions.c")) -except: - pass - -filtering = glob.glob(os.path.join(ROOT,"Source","FilteringFunctions","*.c")) -try: - filtering.remove(os.path.join(ROOT,"Source","FilteringFunctions","FilteringFunctions.c")) - filtering.remove(os.path.join(ROOT,"Source","FilteringFunctions","FilteringFunctionsF16.c")) -except: - pass - -matrix = glob.glob(os.path.join(ROOT,"Source","MatrixFunctions","*.c")) -try: - matrix.remove(os.path.join(ROOT,"Source","MatrixFunctions","MatrixFunctions.c")) - matrix.remove(os.path.join(ROOT,"Source","MatrixFunctions","MatrixFunctionsF16.c")) -except: - pass - -statistics = glob.glob(os.path.join(ROOT,"Source","StatisticsFunctions","*.c")) -try: - statistics.remove(os.path.join(ROOT,"Source","StatisticsFunctions","StatisticsFunctions.c")) - statistics.remove(os.path.join(ROOT,"Source","StatisticsFunctions","StatisticsFunctionsF16.c")) -except: - pass - -complexf = glob.glob(os.path.join(ROOT,"Source","ComplexMathFunctions","*.c")) -try: - complexf.remove(os.path.join(ROOT,"Source","ComplexMathFunctions","ComplexMathFunctions.c")) - complexf.remove(os.path.join(ROOT,"Source","ComplexMathFunctions","ComplexMathFunctionsF16.c")) -except: - pass - -basic = glob.glob(os.path.join(ROOT,"Source","BasicMathFunctions","*.c")) -try: - basic.remove(os.path.join(ROOT,"Source","BasicMathFunctions","BasicMathFunctions.c")) - basic.remove(os.path.join(ROOT,"Source","BasicMathFunctions","BasicMathFunctionsF16.c")) -except: - pass - -controller = glob.glob(os.path.join(ROOT,"Source","ControllerFunctions","*.c")) -try: - controller.remove(os.path.join(ROOT,"Source","ControllerFunctions","ControllerFunctions.c")) -except: - pass - -common = glob.glob(os.path.join(ROOT,"Source","CommonTables","*.c")) -try: - common.remove(os.path.join(ROOT,"Source","CommonTables","CommonTables.c")) - common.remove(os.path.join(ROOT,"Source","CommonTables","CommonTablesF16.c")) -except: - pass - -interpolation = glob.glob(os.path.join(ROOT,"Source","InterpolationFunctions","*.c")) -try: - interpolation.remove(os.path.join(ROOT,"Source","InterpolationFunctions","InterpolationFunctions.c")) - interpolation.remove(os.path.join(ROOT,"Source","InterpolationFunctions","InterpolationFunctionsF16.c")) -except: - pass - -quaternion = glob.glob(os.path.join(ROOT,"Source","QuaternionMathFunctions","*.c")) -try: - quaternion.remove(os.path.join(ROOT,"Source","QuaternionMathFunctions","QuaternionMathFunctions.c")) -except: - pass - -distance = glob.glob(os.path.join(ROOT,"Source","DistanceFunctions","*.c")) -try: - distance.remove(os.path.join(ROOT,"Source","DistanceFunctions","DistanceFunctions.c")) -except: - pass - -bayes = glob.glob(os.path.join(ROOT,"Source","BayesFunctions","*.c")) -try: - bayes.remove(os.path.join(ROOT,"Source","BayesFunctions","BayesFunctions.c")) -except: - pass - -svm = glob.glob(os.path.join(ROOT,"Source","SVMFunctions","*.c")) -try: - svm.remove(os.path.join(ROOT,"Source","SVMFunctions","SVMFunctions.c")) -except: - pass - -window = glob.glob(os.path.join(ROOT,"Source","WindowFunctions","*.c")) -try: - window.remove(os.path.join(ROOT,"Source","WindowFunctions","WindowFunctions.c")) -except: - pass - # Add dependencies -transformMod = transform + common + basic + complexf + fastmath + matrix + statistics -statisticsMod = statistics + common + fastmath + basic -interpolationMod = interpolation + common -filteringMod = filtering + common + support + fastmath + basic -controllerMod = controller + common - -matrixMod = matrix + basic -supportMod = support -complexfMod = complexf + fastmath + common + basic -basicMod = basic -quaternionMod = quaternion -fastmathMod = basic + fastmath + common -distanceMod = distance + common + basic + statistics + fastmath -bayesMod = bayes + fastmath + common + statistics + basic -svmMod = svm + fastmath + common + basic - -windowMod = window +transformMod = [] # transform + common + basic + complexf + fastmath + matrix + statistics +statisticsMod = [] # statistics + common + fastmath + basic +interpolationMod = [] # interpolation + common +filteringMod = [] # filtering + common + support + fastmath + basic +controllerMod = [] # controller + common + +matrixMod = [] # matrix + basic +supportMod = [] # support +complexfMod = [] # complexf + fastmath + common + basic +basicMod = [] # basic +quaternionMod = [] # quaternion +fastmathMod = [] # basic + fastmath + common +distanceMod = [] # distance + common + basic + statistics + fastmath +bayesMod = [] # bayes + fastmath + common + statistics + basic +svmMod = [] # svm + fastmath + common + basic + +windowMod = [] # window filteringMod.append(os.path.join("PythonWrapper","cmsisdsp_pkg","src","cmsisdsp_filtering.c")) matrixMod.append(os.path.join("PythonWrapper","cmsisdsp_pkg","src","cmsisdsp_matrix.c")) @@ -209,35 +98,47 @@ window = list(filter(isnotmissing,list(filter(notf16, windowMod)))) # print(os.path.basename(l)) #quit() -def mkModule(name,srcs,funcDir,newCflags=[]): +def mkModule(name,srcs,funcDir): localinc = os.path.join(ROOT,"Source",funcDir) + libdir = [os.path.join(ROOT,"PythonWrapper","build","bin_dsp")] + lib = ["CMSISDSP"] + extraobjs=[] + + if sys.platform.startswith('linux') or sys.platform.startswith('darwin'): + lib = [] + extraobjs = [os.path.join(ROOT,"PythonWrapper","build_linux","bin_dsp","libCMSISDSP.a")] + libdir = [] + return(Extension(name, sources = (srcs ) , include_dirs = [localinc] + includes + [numpy.get_include()], - extra_compile_args = cflags + newCflags + extra_compile_args = cflags, + library_dirs = libdir, + libraries=lib, + extra_objects=extraobjs )) flagsForCommonWithoutFFT=["-DARM_DSP_CONFIG_TABLES", "-DARM_FAST_ALLOW_TABLES", "-DARM_ALL_FAST_TABLES"] -moduleFiltering = mkModule('cmsisdsp_filtering',filtering,"FilteringFunctions",flagsForCommonWithoutFFT) +moduleFiltering = mkModule('cmsisdsp_filtering',filtering,"FilteringFunctions") moduleMatrix = mkModule('cmsisdsp_matrix',matrix,"MatrixFunctions") moduleSupport = mkModule('cmsisdsp_support',support,"SupportFunctions") -moduleStatistics = mkModule('cmsisdsp_statistics',statistics,"StatisticsFunctions",flagsForCommonWithoutFFT) +moduleStatistics = mkModule('cmsisdsp_statistics',statistics,"StatisticsFunctions") moduleComplexf= mkModule('cmsisdsp_complexf',complexf,"ComplexMathFunctions") moduleBasic = mkModule('cmsisdsp_basic',basic,"BasicMathFunctions") -moduleController = mkModule('cmsisdsp_controller',controller,"ControllerFunctions",flagsForCommonWithoutFFT) +moduleController = mkModule('cmsisdsp_controller',controller,"ControllerFunctions") moduleTransform = mkModule('cmsisdsp_transform',transform,"TransformFunctions") -moduleInterpolation = mkModule('cmsisdsp_interpolation',interpolation,"InterpolationFunctions",flagsForCommonWithoutFFT) +moduleInterpolation = mkModule('cmsisdsp_interpolation',interpolation,"InterpolationFunctions") moduleQuaternion = mkModule('cmsisdsp_quaternion',quaternion,"QuaternionMathFunctions") -moduleFastmath = mkModule('cmsisdsp_fastmath',fastmath,"FastMathFunctions",flagsForCommonWithoutFFT) -moduleDistance = mkModule('cmsisdsp_distance',distance,"DistanceFunctions",flagsForCommonWithoutFFT) -moduleBayes = mkModule('cmsisdsp_bayes',bayes,"BayesFunctions",flagsForCommonWithoutFFT) -moduleSVM = mkModule('cmsisdsp_svm',svm,"SVMFunctions",flagsForCommonWithoutFFT) -moduleWindow = mkModule('cmsisdsp_window',window,"WindowFunctions",flagsForCommonWithoutFFT) +moduleFastmath = mkModule('cmsisdsp_fastmath',fastmath,"FastMathFunctions") +moduleDistance = mkModule('cmsisdsp_distance',distance,"DistanceFunctions") +moduleBayes = mkModule('cmsisdsp_bayes',bayes,"BayesFunctions") +moduleSVM = mkModule('cmsisdsp_svm',svm,"SVMFunctions") +moduleWindow = mkModule('cmsisdsp_window',window,"WindowFunctions") @@ -280,7 +181,7 @@ def build(): moduleWindow ], include_package_data=True, - author = 'Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.', + author = 'Copyright (C) 2010-2023 ARM Limited or its affiliates. All rights reserved.', author_email = 'christophe.favergeon@arm.com', url="https://github.com/ARM-software/CMSIS-DSP", python_requires='>=3.6',