kopia lustrzana https://github.com/OpenRTX/OpenRTX
Updated Module 17 output stream driver to support also double buffered mode
rodzic
c9a4bfb199
commit
163a2ef06a
|
@ -337,7 +337,7 @@ mod17_src = src + stm32f405_src + ['platform/targets/Module17/platform.c',
|
|||
'platform/drivers/NVM/nvmem_Mod17.c',
|
||||
'platform/drivers/baseband/radio_Mod17.cpp',
|
||||
'platform/drivers/audio/inputStream_Mod17.cpp',
|
||||
'platform/drivers/audio/outputStream_Mod17.c',
|
||||
'platform/drivers/audio/outputStream_Mod17.cpp',
|
||||
'platform/drivers/audio/audio_Mod17.c',
|
||||
'platform/drivers/baseband/MCP4551_Mod17.cpp']
|
||||
|
||||
|
|
|
@ -68,8 +68,7 @@ void __attribute__((used)) DMA_Handler()
|
|||
else
|
||||
idleBuf = bufAddr + (bufLen / 2);
|
||||
|
||||
// Stop transfer for linear buffer mode, pending termination request or
|
||||
// DMA error.
|
||||
// Stop transfer for linear buffer mode or pending termination request.
|
||||
if((circularMode == false) || (reqFinish == true))
|
||||
{
|
||||
stopTransfer();
|
||||
|
@ -80,7 +79,7 @@ void __attribute__((used)) DMA_Handler()
|
|||
| DMA_LIFCR_CHTIF2
|
||||
| DMA_LIFCR_CTEIF2;
|
||||
|
||||
// Finally, wake up eventual pending threads
|
||||
// Finally, wake up eventual pending threads
|
||||
if(dmaWaiting == 0) return;
|
||||
dmaWaiting->IRQwakeup();
|
||||
if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
|
||||
* Niccolò Izzo IU2KIN *
|
||||
* Frederik Saraci IU2NRO *
|
||||
* Silvano Seva IU2KWO *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <interfaces/audio_stream.h>
|
||||
#include <interfaces/gpio.h>
|
||||
#include <hwconfig.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int priority = PRIO_BEEP;
|
||||
bool running = false;
|
||||
|
||||
void stopTransfer()
|
||||
{
|
||||
/* Shutdown timer */
|
||||
TIM7->CR1 &= ~TIM_CR1_CEN;
|
||||
|
||||
/* Disable DAC channels and clear underrun flags */
|
||||
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
|
||||
DAC->SR |= DAC_SR_DMAUDR1 | DAC_SR_DMAUDR2;
|
||||
|
||||
/* Stop DMA transfers */
|
||||
DMA1_Stream5->CR &= ~DMA_SxCR_EN;
|
||||
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
|
||||
|
||||
running = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA 1, Stream 5: data transfer for RTX sink
|
||||
*/
|
||||
void __attribute__((used)) DMA1_Stream5_IRQHandler()
|
||||
{
|
||||
stopTransfer();
|
||||
|
||||
DMA1->HIFCR |= DMA_HIFCR_CTCIF5
|
||||
| DMA_HIFCR_CTEIF5;
|
||||
|
||||
NVIC_DisableIRQ(DMA1_Stream5_IRQn);
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA 1, Stream 6: data transfer for speaker sink
|
||||
*/
|
||||
void __attribute__((used)) DMA1_Stream6_IRQHandler()
|
||||
{
|
||||
stopTransfer();
|
||||
|
||||
DMA1->HIFCR |= DMA_HIFCR_CTCIF6
|
||||
| DMA_HIFCR_CTEIF6;
|
||||
|
||||
NVIC_DisableIRQ(DMA1_Stream6_IRQn);
|
||||
}
|
||||
|
||||
streamId outputStream_start(const enum AudioSink destination,
|
||||
const enum AudioPriority prio,
|
||||
stream_sample_t * const buf,
|
||||
const size_t length,
|
||||
const uint32_t sampleRate)
|
||||
{
|
||||
if(destination == SINK_MCU) return -1; /* This device cannot sink to buffer */
|
||||
if(running) /* Check if a stream is already running */
|
||||
{
|
||||
if(prio < priority) return -1; /* Requested priority is lower than current */
|
||||
if(prio > priority) stopTransfer(); /* Stop an ongoing stream with lower priority */
|
||||
while(running) ; /* Same priority, wait for current stream to end */
|
||||
}
|
||||
|
||||
/* This assigment must be thread-safe */
|
||||
__disable_irq();
|
||||
priority = prio;
|
||||
running = true;
|
||||
__enable_irq();
|
||||
|
||||
/*
|
||||
* Convert buffer elements from int16_t to unsigned 16 bit values ranging
|
||||
* from 0 to 4096, as required by DAC. Processing can be done in-place
|
||||
* because the API mandates that the function caller does not modify the
|
||||
* buffer content once this function has been called. Code below exploits
|
||||
* Cortex M4 SIMD instructions for fast execution.
|
||||
*/
|
||||
uint32_t *data = ((uint32_t *) buf);
|
||||
for(size_t i = 0; i < length/2; i++)
|
||||
{
|
||||
uint32_t value = __SADD16(data[i], 0x80008000);
|
||||
data[i] = (value >> 4) & 0x0FFF0FFF;
|
||||
}
|
||||
|
||||
/* Handle last element in case of odd buffer length */
|
||||
if((length % 2) != 0)
|
||||
{
|
||||
int16_t value = buf[length - 1] + 32768;
|
||||
buf[length - 1] = ((uint16_t) value) >> 4;
|
||||
}
|
||||
|
||||
/* Configure GPIOs */
|
||||
gpio_setMode(BASEBAND_TX, INPUT_ANALOG); /* Baseband TX */
|
||||
gpio_setMode(AUDIO_SPK, INPUT_ANALOG); /* Spk output */
|
||||
|
||||
/*
|
||||
* Enable peripherals
|
||||
*/
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_DACEN
|
||||
| RCC_APB1ENR_TIM7EN;
|
||||
__DSB();
|
||||
|
||||
/*
|
||||
* Configure DAC and DMA stream
|
||||
*/
|
||||
if(destination == SINK_RTX)
|
||||
{
|
||||
DAC->CR = DAC_CR_DMAEN1 /* Enable DMA mode */
|
||||
| DAC_CR_TSEL1_1 /* TIM7 TRGO as trigger source */
|
||||
| DAC_CR_TEN1 /* Enable trigger input */
|
||||
| DAC_CR_EN1; /* Enable DAC */
|
||||
|
||||
DMA1_Stream5->NDTR = length;
|
||||
DMA1_Stream5->PAR = ((uint32_t) &(DAC->DHR12R1));
|
||||
DMA1_Stream5->M0AR = ((uint32_t) buf);
|
||||
DMA1_Stream5->CR = DMA_SxCR_CHSEL /* Channel 7 */
|
||||
| DMA_SxCR_PL /* Very high priority */
|
||||
| DMA_SxCR_MSIZE_0 /* 16 bit source size */
|
||||
| DMA_SxCR_PSIZE_0 /* 16 bit destination size */
|
||||
| DMA_SxCR_MINC /* Increment source pointer */
|
||||
| DMA_SxCR_TCIE /* Transfer complete interrupt */
|
||||
| DMA_SxCR_TEIE /* Transfer error interrupt */
|
||||
| DMA_SxCR_DIR_0 /* Memory to peripheral */
|
||||
| DMA_SxCR_EN; /* Start transfer */
|
||||
|
||||
NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn);
|
||||
NVIC_SetPriority(DMA1_Stream5_IRQn, 10);
|
||||
NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
DAC->CR = DAC_CR_DMAEN2 /* Enable DMA mode */
|
||||
| DAC_CR_TSEL2_1 /* TIM7 TRGO as trigger source */
|
||||
| DAC_CR_TEN2 /* Enable trigger input */
|
||||
| DAC_CR_EN2; /* Enable DAC */
|
||||
|
||||
DMA1_Stream6->NDTR = length;
|
||||
DMA1_Stream6->PAR = ((uint32_t) &(DAC->DHR12R2));
|
||||
DMA1_Stream6->M0AR = ((uint32_t) buf);
|
||||
DMA1_Stream6->CR = DMA_SxCR_CHSEL /* Channel 7 */
|
||||
| DMA_SxCR_PL /* Very high priority */
|
||||
| DMA_SxCR_MSIZE_0 /* 16 bit source size */
|
||||
| DMA_SxCR_PSIZE_0 /* 16 bit destination size */
|
||||
| DMA_SxCR_MINC /* Increment source pointer */
|
||||
| DMA_SxCR_TCIE /* Transfer complete interrupt */
|
||||
| DMA_SxCR_TEIE /* Transfer error interrupt */
|
||||
| DMA_SxCR_DIR_0 /* Memory to peripheral */
|
||||
| DMA_SxCR_EN; /* Start transfer */
|
||||
|
||||
NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn);
|
||||
NVIC_SetPriority(DMA1_Stream6_IRQn, 10);
|
||||
NVIC_EnableIRQ(DMA1_Stream6_IRQn);
|
||||
}
|
||||
|
||||
/*
|
||||
* TIM7 for conversion triggering via TIM7_TRGO, that is counter reload.
|
||||
* AP1 frequency is 42MHz but timer runs at 84MHz, tick rate is 1MHz,
|
||||
* reload register is configured based on desired sample rate.
|
||||
*/
|
||||
TIM7->PSC = 83;
|
||||
TIM7->ARR = (1000000/sampleRate) - 1;
|
||||
TIM7->CNT = 0;
|
||||
TIM7->EGR = TIM_EGR_UG;
|
||||
TIM7->CR2 = TIM_CR2_MMS_1;
|
||||
TIM7->CR1 = TIM_CR1_CEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void outputStream_stop(streamId id)
|
||||
{
|
||||
(void) id;
|
||||
|
||||
if(!running) return;
|
||||
|
||||
stopTransfer();
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2021 - 2022 by Federico Amedeo Izzo IU2NUO, *
|
||||
* Niccolò Izzo IU2KIN *
|
||||
* Frederik Saraci IU2NRO *
|
||||
* Silvano Seva IU2KWO *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <kernel/scheduler/scheduler.h>
|
||||
#include <interfaces/audio_stream.h>
|
||||
#include <interfaces/gpio.h>
|
||||
#include <data_conversion.h>
|
||||
#include <hwconfig.h>
|
||||
#include <miosix.h>
|
||||
|
||||
static int priority = PRIO_BEEP;
|
||||
static bool running = false; // Stream is running
|
||||
static bool circularMode = false; // Circular mode enabled
|
||||
static bool reqFinish = false; // Pending termination request
|
||||
static size_t bufLen = 0; // Buffer length
|
||||
static stream_sample_t *bufAddr = 0; // Start address of data buffer, fixed.
|
||||
static stream_sample_t *idleBuf = 0;
|
||||
|
||||
using namespace miosix;
|
||||
static Thread *dmaWaiting = 0;
|
||||
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Stop an ongoing transfer, deactivating timers and DMA stream.
|
||||
*/
|
||||
void stopTransfer()
|
||||
{
|
||||
// Shutdown timer
|
||||
TIM7->CR1 &= ~TIM_CR1_CEN;
|
||||
|
||||
// Disable DAC channels and clear underrun flags
|
||||
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
|
||||
DAC->SR |= DAC_SR_DMAUDR1 | DAC_SR_DMAUDR2;
|
||||
|
||||
// Stop DMA transfers
|
||||
DMA1_Stream5->CR &= ~DMA_SxCR_EN;
|
||||
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
|
||||
|
||||
running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Actual implementation of DMA interrupt handler.
|
||||
*/
|
||||
void __attribute__((used)) DMA_Handler()
|
||||
{
|
||||
// Manage half transfer interrupt
|
||||
if((DMA1->HISR & DMA_HISR_HTIF5) || (DMA1->HISR & DMA_HISR_HTIF6))
|
||||
idleBuf = bufAddr;
|
||||
else
|
||||
idleBuf = bufAddr + (bufLen / 2);
|
||||
|
||||
// Stop transfer for linear buffer mode or pending termination request.
|
||||
if((circularMode == false) || (reqFinish == true))
|
||||
{
|
||||
stopTransfer();
|
||||
}
|
||||
|
||||
// Clear interrupt flags for stream 5
|
||||
if(DMA1->HISR & 0x00000F40)
|
||||
{
|
||||
DMA1->HIFCR = DMA_HIFCR_CTEIF5
|
||||
| DMA_HIFCR_CTCIF5
|
||||
| DMA_HIFCR_CHTIF5;
|
||||
}
|
||||
|
||||
// Clear interrupt flags for stream 6
|
||||
if(DMA1->HISR & 0x003D0000)
|
||||
{
|
||||
DMA1->HIFCR = DMA_HIFCR_CTEIF6
|
||||
| DMA_HIFCR_CTCIF6
|
||||
| DMA_HIFCR_CHTIF6;
|
||||
}
|
||||
|
||||
// Finally, wake up eventual pending threads
|
||||
if(dmaWaiting == 0) return;
|
||||
dmaWaiting->IRQwakeup();
|
||||
if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
|
||||
Scheduler::IRQfindNextThread();
|
||||
dmaWaiting = 0;
|
||||
}
|
||||
|
||||
// DMA 1, Stream 5: data transfer for RTX sink
|
||||
void __attribute__((used)) DMA1_Stream5_IRQHandler()
|
||||
{
|
||||
saveContext();
|
||||
asm volatile("bl _Z11DMA_Handlerv");
|
||||
restoreContext();
|
||||
}
|
||||
|
||||
// DMA 1, Stream 6: data transfer for speaker sink
|
||||
void __attribute__((used)) DMA1_Stream6_IRQHandler()
|
||||
{
|
||||
saveContext();
|
||||
asm volatile("bl _Z11DMA_Handlerv");
|
||||
restoreContext();
|
||||
}
|
||||
|
||||
|
||||
streamId outputStream_start(const enum AudioSink destination,
|
||||
const enum AudioPriority prio,
|
||||
stream_sample_t * const buf,
|
||||
const size_t length,
|
||||
const enum BufMode mode,
|
||||
const uint32_t sampleRate)
|
||||
{
|
||||
// Sanity check
|
||||
if((buf == NULL) || (length == 0) || (sampleRate == 0)) return -1;
|
||||
|
||||
// This device cannot sink to buffers
|
||||
if(destination == SINK_MCU) return -1;
|
||||
|
||||
// Check if an output stream is already opened and, in case, handle priority.
|
||||
if(running)
|
||||
{
|
||||
if(prio < priority) return -1; // Lower priority, reject.
|
||||
if(prio > priority) stopTransfer(); // Higher priority, takes over.
|
||||
while(running) ; // Same priority, wait.
|
||||
}
|
||||
|
||||
// Thread-safe block: assign priority, set stream as running and lock "beeps"
|
||||
__disable_irq();
|
||||
priority = prio;
|
||||
running = true;
|
||||
__enable_irq();
|
||||
|
||||
/*
|
||||
* Convert buffer elements from int16_t to unsigned 8 bit values, as
|
||||
* required by tone generator. Processing can be done in-place because the
|
||||
* API mandates that the function caller does not modify the buffer content
|
||||
* once this function has been called.
|
||||
*/
|
||||
S16toU12(buf, length);
|
||||
bufAddr = buf;
|
||||
bufLen = length;
|
||||
idleBuf = bufAddr + (bufLen / 2);
|
||||
|
||||
// Configure GPIOs
|
||||
gpio_setMode(BASEBAND_TX, INPUT_ANALOG); /* Baseband TX */
|
||||
gpio_setMode(AUDIO_SPK, INPUT_ANALOG); /* Spk output */
|
||||
|
||||
/*
|
||||
* Enable peripherals
|
||||
*/
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_DACEN
|
||||
| RCC_APB1ENR_TIM7EN;
|
||||
__DSB();
|
||||
|
||||
/*
|
||||
* Configure DAC and DMA stream
|
||||
*/
|
||||
uint32_t circular = 0;
|
||||
if(mode == BUF_CIRC_DOUBLE)
|
||||
{
|
||||
circular = DMA_SxCR_CIRC // Circular buffer mode
|
||||
| DMA_SxCR_HTIE; // Half transfer interrupt
|
||||
circularMode = true;
|
||||
}
|
||||
|
||||
if(destination == SINK_RTX)
|
||||
{
|
||||
DAC->CR = DAC_CR_DMAEN1 // Enable DMA mode
|
||||
| DAC_CR_TSEL1_1 // TIM7 TRGO as trigger source
|
||||
| DAC_CR_TEN1 // Enable trigger input
|
||||
| DAC_CR_EN1; // Enable DAC
|
||||
|
||||
DMA1_Stream5->NDTR = length;
|
||||
DMA1_Stream5->PAR = reinterpret_cast< uint32_t >(&(DAC->DHR12R1));
|
||||
DMA1_Stream5->M0AR = reinterpret_cast< uint32_t >(buf);
|
||||
DMA1_Stream5->CR = DMA_SxCR_CHSEL // Channel 7
|
||||
| DMA_SxCR_PL // Very high priority
|
||||
| DMA_SxCR_MSIZE_0 // 16 bit source size
|
||||
| DMA_SxCR_PSIZE_0 // 16 bit destination size
|
||||
| DMA_SxCR_MINC // Increment source pointer
|
||||
| DMA_SxCR_TCIE // Transfer complete interrupt
|
||||
| DMA_SxCR_TEIE // Transfer error interrupt
|
||||
| DMA_SxCR_DIR_0 // Memory to peripheral
|
||||
| circular // Circular mode
|
||||
| DMA_SxCR_EN; // Start transfer
|
||||
|
||||
NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn);
|
||||
NVIC_SetPriority(DMA1_Stream5_IRQn, 10);
|
||||
NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
}
|
||||
else
|
||||
{
|
||||
DAC->CR = DAC_CR_DMAEN2 // Enable DMA mode
|
||||
| DAC_CR_TSEL2_1 // TIM7 TRGO as trigger source
|
||||
| DAC_CR_TEN2 // Enable trigger input
|
||||
| DAC_CR_EN2; // Enable DAC
|
||||
|
||||
DMA1_Stream6->NDTR = length;
|
||||
DMA1_Stream6->PAR = reinterpret_cast< uint32_t >(&(DAC->DHR12R2));
|
||||
DMA1_Stream6->M0AR = reinterpret_cast< uint32_t >(buf);
|
||||
DMA1_Stream6->CR = DMA_SxCR_CHSEL // Channel 7
|
||||
| DMA_SxCR_PL // Very high priority
|
||||
| DMA_SxCR_MSIZE_0 // 16 bit source size
|
||||
| DMA_SxCR_PSIZE_0 // 16 bit destination size
|
||||
| DMA_SxCR_MINC // Increment source pointer
|
||||
| DMA_SxCR_TCIE // Transfer complete interrupt
|
||||
| DMA_SxCR_TEIE // Transfer error interrupt
|
||||
| DMA_SxCR_DIR_0 // Memory to peripheral
|
||||
| circular // Circular mode
|
||||
| DMA_SxCR_EN; // Start transfer
|
||||
|
||||
NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn);
|
||||
NVIC_SetPriority(DMA1_Stream6_IRQn, 10);
|
||||
NVIC_EnableIRQ(DMA1_Stream6_IRQn);
|
||||
}
|
||||
|
||||
/*
|
||||
* TIM7 for conversion triggering via TIM7_TRGO, that is counter reload.
|
||||
* AP1 frequency is 42MHz but timer runs at 84MHz, tick rate is 1MHz,
|
||||
* reload register is configured based on desired sample rate.
|
||||
*/
|
||||
TIM7->CNT = 0;
|
||||
TIM7->PSC = 0;
|
||||
TIM7->ARR = 84000000/sampleRate;
|
||||
TIM7->EGR = TIM_EGR_UG;
|
||||
TIM7->CR2 = TIM_CR2_MMS_1;
|
||||
TIM7->CR1 = TIM_CR1_CEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream_sample_t *outputStream_getIdleBuffer(const streamId id)
|
||||
{
|
||||
(void) id;
|
||||
|
||||
if(!circularMode) return nullptr;
|
||||
|
||||
return idleBuf;
|
||||
}
|
||||
|
||||
bool outputStream_sync(const streamId id, const bool bufChanged)
|
||||
{
|
||||
(void) id;
|
||||
|
||||
if(circularMode && bufChanged)
|
||||
{
|
||||
stream_sample_t *ptr = outputStream_getIdleBuffer(id);
|
||||
S16toU12(ptr, bufLen/2);
|
||||
}
|
||||
|
||||
// Enter in critical section until the end of the function
|
||||
FastInterruptDisableLock dLock;
|
||||
|
||||
Thread *curThread = Thread::IRQgetCurrentThread();
|
||||
if((dmaWaiting != 0) && (dmaWaiting != curThread)) return false;
|
||||
dmaWaiting = curThread;
|
||||
|
||||
do
|
||||
{
|
||||
Thread::IRQwait();
|
||||
{
|
||||
// Re-enable interrupts while waiting for IRQ
|
||||
FastInterruptEnableLock eLock(dLock);
|
||||
Thread::yield();
|
||||
}
|
||||
}
|
||||
while((dmaWaiting != 0) && (running == true));
|
||||
|
||||
dmaWaiting = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void outputStream_stop(const streamId id)
|
||||
{
|
||||
(void) id;
|
||||
|
||||
reqFinish = true;
|
||||
}
|
||||
|
||||
void outputStream_terminate(const streamId id)
|
||||
{
|
||||
(void) id;
|
||||
|
||||
FastInterruptDisableLock dLock;
|
||||
|
||||
stopTransfer();
|
||||
|
||||
DMA1->HIFCR = DMA_HIFCR_CTEIF5
|
||||
| DMA_HIFCR_CTCIF5
|
||||
| DMA_HIFCR_CHTIF5;
|
||||
|
||||
DMA1->HIFCR = DMA_HIFCR_CTEIF6
|
||||
| DMA_HIFCR_CTCIF6
|
||||
| DMA_HIFCR_CHTIF6;
|
||||
}
|
Ładowanie…
Reference in New Issue