Update to the Python wrapper

Corrected issue with RFFT APIs
Added some features to compute graph

Improved documentation related to RFFT
Changed how Python wrapper is built (to prepare fro future
evolution).
pull/94/head
Christophe Favergeon 3 years ago
parent 0fe2214dc7
commit 8b49478b1f

3
.gitignore vendored

@ -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/

@ -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<T>`
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:

@ -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 <stddef.h>
#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

@ -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

@ -1,69 +0,0 @@
#ifndef _AUDIOCONFIG_H_
#define _AUDIOCONFIG_H_
// <<< Use Configuration Wizard in Context Menu >>>
// <e>Audio Configuration for RX
#ifndef AUDIO_DRV_RX_ENABLED
#define AUDIO_DRV_RX_ENABLED 1
#endif
// <o>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
// <o>Number of samples <256=> 256 <512=> 512 <1024=> 1024 <2048=> 2048
// <i> Must be consistent with the settings of the Audio source
#ifndef AUDIO_DRV_NBSAMPLES_RX
#define AUDIO_DRV_NBSAMPLES_RX 2048
#endif
// <o>Number of channels <1=> Mono <2=> Stereo
#ifndef AUDIO_DRV_NBCHANNELS_RX
#define AUDIO_DRV_NBCHANNELS_RX 1U
#endif
// <o>Channel encoding <2=> 16 Bits
#ifndef AUDIO_DRV_CHANNEL_ENCODING_RX
#define AUDIO_DRV_CHANNEL_ENCODING_RX 2U
#endif
// </e>
// <e>Audio Configuration for TX
#ifndef AUDIO_DRV_TX_ENABLED
#define AUDIO_DRV_TX_ENABLED 1
#endif
// <o>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
// <o>Number of samples <256=> 256 <512=> 512 <1024=> 1024 <2048=> 2048
// <i> Must be consistent with the settings of the Audio source
#ifndef AUDIO_DRV_NBSAMPLES_TX
#define AUDIO_DRV_NBSAMPLES_TX 2048
#endif
// <o>Number of channels <1=> Mono <2=> Stereo
#ifndef AUDIO_DRV_NBCHANNELS_TX
#define AUDIO_DRV_NBCHANNELS_TX 1U
#endif
// <o>Channel encoding <2=> 16 Bits
#ifndef AUDIO_DRV_CHANNEL_ENCODING_TX
#define AUDIO_DRV_CHANNEL_ENCODING_TX 2U
#endif
// </e>
// <q> 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

@ -1,26 +0,0 @@
#ifndef _RINGCONFIG_H_
#define _RINGCONFIG_H_
// <<< Use Configuration Wizard in Context Menu >>>
// <h>Ring Buffer Configuration
// <o>Number of buffers <2=> 2 <4=> 4 <8=> 8 <16=> 16 <32=> 32
#ifndef RING_NBBUFS
#define RING_NBBUFS 4
#endif
// </h>
// <<< 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

@ -1,35 +0,0 @@
#ifndef _VIDEOCONFIG_H_
#define _VIDEOCONFIG_H_
// <<< Use Configuration Wizard in Context Menu >>>
// <h>Video Configuration
// <o>Width in pixels <16-640>
#ifndef VIDEO_DRV_WIDTH
#define VIDEO_DRV_WIDTH 32
#endif
// <o>Height in pixels <16-640>
#ifndef VIDEO_DRV_HEIGHT
#define VIDEO_DRV_HEIGHT 32
#endif
// <o>Pixel size in bytes <1=> 1 <2=> 2
#ifndef VIDEO_DRV_PIXEL_SIZE
#define VIDEO_DRV_PIXEL_SIZE 1
#endif
// <o>Frame rate <10=> 10 <25=> 25 <30=> 30 <60=> 60
#ifndef VIDEO_DRV_FRAME_RATE
#define VIDEO_DRV_FRAME_RATE 10
#endif
// </h>
// <<< end of configuration section >>>
#define CGSTATIC_VIDEO_CONFIG
#endif

@ -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.

@ -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();
}

@ -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_*/

@ -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);
}
}

@ -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

@ -1,202 +0,0 @@
#include <stddef.h>
#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<uint32_t>(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<uint32_t>(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;
}

@ -1,292 +0,0 @@
/*
* Copyright (c) 2021 Arm Limited. All rights reserved.
*/
#include <stddef.h>
#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;
}

@ -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 <stdint.h>
/* 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 */

@ -1,101 +0,0 @@
#include <stddef.h>
#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<uint32_t>(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;
}

@ -1,232 +0,0 @@
/*
* Copyright (c) 2021 Arm Limited. All rights reserved.
*/
#include <stddef.h>
#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;
}

@ -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 <stdint.h>
/* 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 */

@ -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<typename IN, int inputSize>
class StreamingSink: public GenericSink<IN, inputSize>
{
public:
StreamingSink(FIFOBase<IN> &src,ring_config_t *config):
GenericSink<IN,inputSize>(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_ */

@ -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<typename OUT,int outputSize>
class StreamingSource: public GenericSource<OUT,outputSize>
{
public:
StreamingSource(FIFOBase<OUT> &dst,ring_config_t *config):
GenericSource<OUT,outputSize>(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_ */

@ -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<T,length,0,0>: public FIFOBase<T>
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<T,length,1,0>: public FIFOBase<T>
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<T,length,0,1>: public FIFOBase<T>
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()
{

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.15)
cmake_minimum_required (VERSION 3.21)
include(CMakePrintHelpers)
set(Python_FIND_REGISTRY "LAST")

@ -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<float32_t,7,float32_t,5> filter(fifo0,fifo1,4,"Test",someVariable);
ProcessingNode<float32_t,7,float32_t,5> filter(fifo0,fifo1,4,testString,someVariable);
Sink<float32_t,5> sink(fifo1);
Source<float32_t,5> source(fifo0);

@ -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
}

@ -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"

@ -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;
}

@ -31,6 +31,8 @@
#include <iostream>
#include <cstdio>
#include "NullSink.h"
static int count=0;
template<typename OUT,int outputSize>

@ -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<int16_t,FIFOSIZE3,0,1> fifo3(buf4);
FIFO<int16_t,FIFOSIZE4,0,1> fifo4(buf5);
FIFO<int16_t,FIFOSIZE5,0,1> fifo5(buf6);
FIFO<int16_t,FIFOSIZE6,0,1> fifo6(buf7);
FIFO<int16_t,FIFOSIZE7,0,1> fifo7(buf8);
CG_BEFORE_NODE_INIT;
/*
Create node objects
*/
Duplicate2<int16_t,1,int16_t,1,int16_t,1> dup0(fifo3,fifo4,fifo5);
ProcessingOddEven<int16_t,1,int16_t,1,int16_t,1> proc(fifo0,fifo1,fifo2);
SinkAsync<int16_t,1> sinka(fifo4);
SinkAsync<int16_t,1> sinkb(fifo5);
SourceEven<int16_t,1> sourceEven(fifo1);
SourceOdd<int16_t,1> sourceOdd(fifo0);
NullSink<int16_t,1> debug(fifo4);
Duplicate2<int16_t,1,int16_t,1,int16_t,1> dup0(fifo2,fifo3,fifo4);
Duplicate2<int16_t,1,int16_t,1,int16_t,1> dup1(fifo5,fifo6,fifo7);
ProcessingOddEven<int16_t,1,int16_t,1,int16_t,1> proc(fifo3,fifo0,fifo1);
SinkAsync<int16_t,1> sinka(fifo6);
SinkAsync<int16_t,1> sinkb(fifo7);
SourceEven<int16_t,1> sourceEven(fifo0);
SourceOdd<int16_t,1> 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();
}

@ -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

@ -16,8 +16,17 @@ compute1 [label=<
</TR>
</TABLE>>];
debug [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">debug<BR/>(NullSink)</TD>
</TR>
</TABLE>>];
dup0 [shape=point,label=dup0]
dup1 [shape=point,label=dup1]
proc [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
@ -64,38 +73,50 @@ sourceOdd [label=<
sourceOdd:i -> proc:ia [label="s16(2)"
sourceEven:i -> proc:ib [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>]
sourceEven:i -> proc:ib [label="s16(2)"
proc:o -> compute1:i [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>]
proc:o -> compute1:i [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
sourceOdd:i ->
dup0 [label="s16(2)"
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>]
dup0 -> proc:ia [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
]
dup0 -> debug:i [label="s16(3)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
]
compute1:i ->
dup0 [label="s16(2)"
dup1 [label="s16(2)"
,taillabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>]
dup0 -> sinka:i [label="s16(2)"
dup1 -> sinka:i [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
]
dup0 -> sinkb:i [label="s16(2)"
dup1 -> sinkb:i [label="s16(2)"
,headlabel=<<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>
]

@ -1,4 +1,7 @@
dist/
build/
examples/rec_2.dat
build/bin_dsp
build/cmake_install.cmake
build/CMakeFiles
build/Makefile
build/CMakeCache.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)

@ -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

@ -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" ..

@ -0,0 +1,5 @@
rm -f CMakeCache.txt
rm -rf CMakeFiles
rm -f Makefile
rm -rf bin_dsp
rm -f cmake_install.cmake

@ -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

@ -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);

@ -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)

@ -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

@ -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()

@ -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)

@ -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.

@ -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.

@ -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

@ -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(

@ -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).

@ -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(

@ -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(

@ -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

@ -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

@ -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):

@ -1,2 +1,2 @@
# Python wrapper version
__version__ = "1.9.5"
__version__ = "1.9.6"

@ -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',

Loading…
Cancel
Save