Fixed jitter in M17 baseband signal generation
This commit is contained in:
parent
ce10edfb47
commit
a3b7b490d4
|
|
@ -57,13 +57,17 @@ public:
|
|||
|
||||
/**
|
||||
* Generate and transmit the baseband signal obtained by 4FSK modulation of
|
||||
* a given block of data.
|
||||
* a given block of data. When called for the first time, this function
|
||||
* starts baseband transmission.
|
||||
*
|
||||
* @param sync: synchronisation word to be prepended to data block.
|
||||
* @param data: data block to be transmitted.
|
||||
* @param isLast: flag signalling that current block is the last one being
|
||||
* transmitted.
|
||||
*/
|
||||
void send(const std::array< uint8_t, 2 >& sync,
|
||||
const std::array< uint8_t, 46 >& data);
|
||||
const std::array< uint8_t, 46 >& data,
|
||||
const bool isLast = false);
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -110,6 +114,8 @@ private:
|
|||
int16_t *baseband_buffer; ///< Buffer for baseband audio handling.
|
||||
dataBuffer_t *activeBuffer; ///< Half baseband buffer, in transmission.
|
||||
dataBuffer_t *idleBuffer; ///< Half baseband buffer, free for processing.
|
||||
bool txRunning; ///< Transmission running.
|
||||
bool stopTx; ///< Stop transmission request.
|
||||
};
|
||||
|
||||
#endif /* M17_MODULATOR_H */
|
||||
|
|
|
|||
|
|
@ -89,9 +89,10 @@ void M17Modulator::init()
|
|||
*/
|
||||
|
||||
baseband_buffer = new int16_t[2 * M17_FRAME_SAMPLES];
|
||||
activeBuffer = new (baseband_buffer) dataBuffer_t;
|
||||
idleBuffer = new (baseband_buffer) dataBuffer_t;
|
||||
int16_t *ptr = baseband_buffer + activeBuffer->size();
|
||||
idleBuffer = new (ptr) dataBuffer_t;
|
||||
activeBuffer = new (ptr) dataBuffer_t;
|
||||
txRunning = false;
|
||||
}
|
||||
|
||||
void M17Modulator::terminate()
|
||||
|
|
@ -103,7 +104,8 @@ void M17Modulator::terminate()
|
|||
}
|
||||
|
||||
void M17Modulator::send(const std::array< uint8_t, 2 >& sync,
|
||||
const std::array< uint8_t, 46 >& data)
|
||||
const std::array< uint8_t, 46 >& data,
|
||||
const bool isLast)
|
||||
{
|
||||
auto sync1 = byteToSymbols(sync[0]);
|
||||
auto sync2 = byteToSymbols(sync[1]);
|
||||
|
|
@ -117,6 +119,9 @@ void M17Modulator::send(const std::array< uint8_t, 2 >& sync,
|
|||
it = std::copy(sym.begin(), sym.end(), it);
|
||||
}
|
||||
|
||||
// If last frame, signal stop of transmission
|
||||
if(isLast) stopTx = true;
|
||||
|
||||
generateBaseband();
|
||||
emitBaseband();
|
||||
}
|
||||
|
|
@ -149,11 +154,29 @@ void M17Modulator::emitBaseband()
|
|||
idleBuffer->at(i) = shifted_sample;
|
||||
}
|
||||
|
||||
toneGen_waitForStreamEnd();
|
||||
std::swap(idleBuffer, activeBuffer);
|
||||
if(txRunning == false)
|
||||
{
|
||||
// First run, start transmission
|
||||
toneGen_playAudioStream(reinterpret_cast< uint16_t *>(baseband_buffer),
|
||||
2*M17_FRAME_SAMPLES, M17_RTX_SAMPLE_RATE, true);
|
||||
txRunning = true;
|
||||
stopTx = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transmission is ongoing, syncronise with stream end before proceeding
|
||||
toneGen_waitForStreamEnd();
|
||||
|
||||
toneGen_playAudioStream(reinterpret_cast< uint16_t *>(activeBuffer->data()),
|
||||
activeBuffer->size(), M17_RTX_SAMPLE_RATE);
|
||||
// Check if transmission stop is requested
|
||||
if(stopTx == true)
|
||||
{
|
||||
toneGen_stopAudioStream();
|
||||
stopTx = false;
|
||||
txRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(idleBuffer, activeBuffer);
|
||||
}
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
void M17Modulator::emitBaseband()
|
||||
|
|
|
|||
|
|
@ -120,5 +120,6 @@ void M17Transmitter::send(const payload_t& payload, const bool isLast)
|
|||
|
||||
interleave(frame);
|
||||
decorrelate(frame);
|
||||
modulator.send(DATA_SYNC_WORD, frame);
|
||||
|
||||
modulator.send(DATA_SYNC_WORD, frame, isLast);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ uint32_t beepTableIncr = 0; // "beep" sine table index increment per tick
|
|||
uint32_t beepTimerCount = 0; // Downcounter for timed "beep"
|
||||
uint8_t beepVolume = 0; // "beep" volume level
|
||||
|
||||
bool tonesLocked = false; // If true tone channel is in use by FSK/playback
|
||||
bool tonesLocked = false; // If true tone channel is in use by FSK/playback
|
||||
bool circularMode = false; // Circular mode enabled
|
||||
|
||||
using namespace miosix;
|
||||
Thread *dmaWaiting = 0;
|
||||
|
|
@ -98,19 +99,22 @@ void __attribute__((used)) TIM8_TRG_COM_TIM14_IRQHandler()
|
|||
*/
|
||||
void __attribute__((used)) DMA_Handler()
|
||||
{
|
||||
DMA1->LIFCR |= DMA_LIFCR_CTCIF2 // Clear interrupt flags
|
||||
DMA1->LIFCR |= DMA_LIFCR_CTCIF2 // Clear interrupt flags
|
||||
| DMA_LIFCR_CHTIF2
|
||||
| DMA_LIFCR_CTEIF2;
|
||||
|
||||
TIM7->CR1 = 0; // End of transfer, stop TIM7
|
||||
TIM3->CCER &= ~TIM_CCER_CC3E; // Turn off compare channel
|
||||
if(circularMode == false)
|
||||
{
|
||||
|
||||
RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN; // Turn off DMA
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; // Turn off TIM7
|
||||
__DSB();
|
||||
TIM7->CR1 = 0; // End of transfer, stop TIM7
|
||||
TIM3->CCER &= ~TIM_CCER_CC3E; // Turn off compare channel
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN; // Turn off TIM7
|
||||
__DSB();
|
||||
|
||||
tonesLocked = false; // Finally, unlock tones
|
||||
tonesLocked = false; // Finally, unlock tones
|
||||
}
|
||||
|
||||
if(dmaWaiting == 0) return; // Wake up eventual pending threads
|
||||
if(dmaWaiting == 0) return; // Wake up eventual pending threads
|
||||
dmaWaiting->IRQwakeup();
|
||||
if(dmaWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
|
||||
Scheduler::IRQfindNextThread();
|
||||
|
|
@ -251,7 +255,7 @@ void toneGen_encodeAFSK1200(const uint8_t* buf, const size_t len)
|
|||
}
|
||||
|
||||
void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
|
||||
const uint32_t sampleRate)
|
||||
const uint32_t sampleRate, const bool circMode)
|
||||
{
|
||||
if((buf == NULL) || (len == 0) || (sampleRate == 0)) return;
|
||||
|
||||
|
|
@ -270,7 +274,7 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
|
|||
* Timebase for triggering of DMA transfers.
|
||||
* Bus frequency is 84MHz.
|
||||
*/
|
||||
uint32_t ratio = (84000000/sampleRate) - 1;
|
||||
uint32_t ratio = (84000000/sampleRate);
|
||||
|
||||
TIM7->CNT = 0;
|
||||
TIM7->PSC = 0;
|
||||
|
|
@ -291,9 +295,18 @@ void toneGen_playAudioStream(const uint16_t* buf, const size_t len,
|
|||
| DMA_SxCR_MINC // Increment source pointer
|
||||
| DMA_SxCR_DIR_0 // Memory to peripheral
|
||||
| DMA_SxCR_TCIE // Transfer complete interrupt
|
||||
| DMA_SxCR_TEIE // Transfer error interrupt
|
||||
| DMA_SxCR_EN; // Enable transfer
|
||||
| DMA_SxCR_TEIE; // Transfer error interrupt
|
||||
|
||||
if(circMode)
|
||||
{
|
||||
DMA1_Stream2->CR |= DMA_SxCR_CIRC // Circular buffer mode
|
||||
| DMA_SxCR_HTIE; // Half transfer interrupt
|
||||
circularMode = true;
|
||||
}
|
||||
|
||||
DMA1_Stream2->CR |= DMA_SxCR_EN; // Enable transfer
|
||||
|
||||
// Enable DMA interrupts
|
||||
NVIC_ClearPendingIRQ(DMA1_Stream2_IRQn);
|
||||
NVIC_SetPriority(DMA1_Stream2_IRQn, 10);
|
||||
NVIC_EnableIRQ(DMA1_Stream2_IRQn);
|
||||
|
|
@ -346,13 +359,27 @@ void toneGen_stopAudioStream()
|
|||
TIM7->CR1 = 0;
|
||||
TIM3->CCER &= ~TIM_CCER_CC3E;
|
||||
|
||||
// Shut down TIM7 and DMA
|
||||
RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
|
||||
// Stop DMA transfer and clear pending interrupt flags
|
||||
DMA1_Stream2->CR = 0;
|
||||
DMA1_Stream2->M0AR = 0;
|
||||
DMA1->LIFCR |= DMA_LIFCR_CTCIF2
|
||||
| DMA_LIFCR_CHTIF2
|
||||
| DMA_LIFCR_CTEIF2;
|
||||
|
||||
// Shut down TIM7 clock
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_TIM7EN;
|
||||
__DSB();
|
||||
|
||||
// Unlock tones and wake up the thread waiting for completion
|
||||
tonesLocked = false;
|
||||
if(dmaWaiting) dmaWaiting->IRQwakeup();
|
||||
if(dmaWaiting)
|
||||
{
|
||||
dmaWaiting->IRQwakeup();
|
||||
dmaWaiting = 0;
|
||||
}
|
||||
|
||||
// Clear flag for circular double buffered mode
|
||||
circularMode = false;
|
||||
}
|
||||
|
||||
bool toneGen_toneBusy()
|
||||
|
|
|
|||
|
|
@ -113,9 +113,11 @@ void toneGen_encodeAFSK1200(const uint8_t *buf, const size_t len);
|
|||
* @param buf: pointer to a buffer containing the audio samples.
|
||||
* @param len: length of the data buffer.
|
||||
* @param sampleRate: sample rate of the audio stream in samples per second.
|
||||
* @param circMode: treat buf as a double circular buffer, continuously
|
||||
* reproducing its content.
|
||||
*/
|
||||
void toneGen_playAudioStream(const uint16_t *buf, const size_t len,
|
||||
const uint32_t sampleRate);
|
||||
const uint32_t sampleRate, const bool circMode);
|
||||
|
||||
/**
|
||||
* When called, this function blocks the execution flow until the reproduction
|
||||
|
|
@ -128,7 +130,7 @@ bool toneGen_waitForStreamEnd();
|
|||
|
||||
/**
|
||||
* Interrupt the ongoing reproduction of an audio stream, also making the
|
||||
* toneGen_playAudioStream return to the caller.
|
||||
* toneGen_waitForStreamEnd return to the caller.
|
||||
*/
|
||||
void toneGen_stopAudioStream();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue