Skip to content

Commit

Permalink
Fixed ARM64 bug, when not using DMA
Browse files Browse the repository at this point in the history
  • Loading branch information
markondej committed Aug 14, 2023
1 parent 019f39c commit ddfcf6a
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 86 deletions.
2 changes: 1 addition & 1 deletion mailbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "mailbox.h"
#include "mailbox.hpp"

#define PAGE_SIZE (4*1024)

Expand Down
159 changes: 75 additions & 84 deletions transmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
#define BCM2711_PLLD_FREQ 750

#define GPIO_BASE_OFFSET 0x00200000
#define TIMER_BASE_OFFSET 0x00003000

#define CLK0_BASE_OFFSET 0x00101070
#define CLK1_BASE_OFFSET 0x00101078
Expand Down Expand Up @@ -100,16 +99,6 @@
#define BUFFER_TIME 1000000
#define PAGE_SIZE 4096

struct TimerRegisters {
uint32_t ctlStatus;
uint32_t low;
uint32_t high;
uint32_t c0;
uint32_t c1;
uint32_t c2;
uint32_t c3;
};

struct ClockRegisters {
uint32_t ctl;
uint32_t div;
Expand Down Expand Up @@ -359,6 +348,10 @@ Transmitter::Transmitter()
}

Transmitter::~Transmitter() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&]() -> bool {
return !txThread.joinable() && !enable;
});
if (output != nullptr) {
delete output;
}
Expand Down Expand Up @@ -386,6 +379,11 @@ void Transmitter::Transmit(WaveReader &reader, float frequency, float bandwidth,
delete output;
output = nullptr;
}
{
std::lock_guard<std::mutex> lock(mtx);
enable = false;
}
cv.notify_all();
};
try {
if (dmaChannel != 0xff) {
Expand All @@ -408,66 +406,6 @@ void Transmitter::Stop()
cv.notify_all();
}

void Transmitter::TransmitViaCpu(WaveReader &reader, ClockOutput &output, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange)
{
std::vector<Sample> samples;
unsigned sampleOffset = 0;

bool eof = false, stop = false, start = true;

std::thread transmitterThread(Transmitter::TransmitterThread, this, &output, sampleRate, clockDivisor, divisorRange, &sampleOffset, &samples, &stop);

auto finally = [&]() {
{
std::lock_guard<std::mutex> lock(mtx);
stop = true;
cv.notify_one();
}
transmitterThread.join();
samples.clear();
enable = false;
};

try {
while (!eof) {
std::unique_lock<std::mutex> lock(mtx);
if (!start) {
cv.wait(lock, [&]() -> bool {
return samples.empty() || !enable || stop;
});
} else {
start = false;
}
if (!enable) {
break;
}
if (stop) {
throw std::runtime_error("Transmitter thread has unexpectedly exited");
}
if (samples.empty()) {
if (!reader.SetSampleOffset(sampleOffset + bufferSize)) {
break;
}
lock.unlock();
samples = reader.GetSamples(bufferSize, enable, mtx);
lock.lock();
if (samples.empty()) {
break;
}
eof = samples.size() < bufferSize;
lock.unlock();
cv.notify_one();
} else {
lock.unlock();
}
}
} catch (...) {
finally();
throw;
}
finally();
}

void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange, unsigned dmaChannel)
{
if (dmaChannel > 15) {
Expand Down Expand Up @@ -526,8 +464,6 @@ void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsign
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
samples.clear();
std::lock_guard<std::mutex> lock(mtx);
enable = false;
};
try {
while (!eof) {
Expand Down Expand Up @@ -559,14 +495,69 @@ void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsign
finally();
}

void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output, unsigned sampleRate, unsigned clockDivisor, unsigned divisorRange, unsigned *sampleOffset, std::vector<Sample> *samples, bool *stop)
void Transmitter::TransmitViaCpu(WaveReader &reader, ClockOutput &output, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange)
{
std::vector<Sample> samples;
unsigned sampleOffset = 0;

bool eof = false, stop = false, start = true;

txThread = std::thread(Transmitter::TransmitterThread, this, &output, sampleRate, clockDivisor, divisorRange, &sampleOffset, &samples, &stop);

auto finally = [&]() {
{
std::lock_guard<std::mutex> lock(mtx);
stop = true;
}
cv.notify_all();
txThread.join();
samples.clear();
};

try {
Peripherals &peripherals = Peripherals::GetInstance();
while (!eof) {
std::unique_lock<std::mutex> lock(mtx);
if (!start) {
cv.wait(lock, [&]() -> bool {
return samples.empty() || !enable || stop;
});
}
if (!enable) {
break;
}
if (stop) {
throw std::runtime_error("Transmitter thread has unexpectedly exited");
}
if (samples.empty()) {
if (!reader.SetSampleOffset(sampleOffset + (start ? 0 : bufferSize))) {
break;
}
lock.unlock();
samples = reader.GetSamples(bufferSize, enable, mtx);
lock.lock();
if (samples.empty()) {
break;
}
eof = samples.size() < bufferSize;
lock.unlock();
cv.notify_all();
} else {
lock.unlock();
}
start = false;
}
} catch (...) {
finally();
throw;
}
finally();
}

volatile TimerRegisters *timer = reinterpret_cast<TimerRegisters *>(peripherals.GetVirtualAddress(TIMER_BASE_OFFSET));
uint64_t current = *(reinterpret_cast<volatile uint64_t *>(&timer->low));
uint64_t playbackStart = current, start = current;
void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output, unsigned sampleRate, unsigned clockDivisor, unsigned divisorRange, unsigned *sampleOffset, std::vector<Sample> *samples, bool *stop)
{
try {
auto playbackStart = std::chrono::system_clock::now();
std::chrono::system_clock::time_point current, start;

while (true) {
std::vector<Sample> loadedSamples;
Expand All @@ -578,11 +569,11 @@ void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output,
if (*stop) {
break;
}
start = current = *(reinterpret_cast<volatile uint64_t *>(&timer->low));
*sampleOffset = (current - playbackStart) * sampleRate / 1000000;
start = current = std::chrono::system_clock::now();
*sampleOffset = std::chrono::duration_cast<std::chrono::microseconds>(current - playbackStart).count() * sampleRate / 1000000;
loadedSamples = std::move(*samples);
lock.unlock();
instance->cv.notify_one();
instance->cv.notify_all();

unsigned offset = 0;

Expand All @@ -595,15 +586,15 @@ void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output,
instance->output->SetDivisor(clockDivisor - static_cast<int>(round(value * divisorRange)));
while (offset == prevOffset) {
std::this_thread::yield(); // asm("nop");
current = *(reinterpret_cast<volatile uint64_t *>(&timer->low));;
offset = (current - start) * sampleRate / 1000000;
current = std::chrono::system_clock::now();
offset = std::chrono::duration_cast<std::chrono::microseconds>(current - start).count() * sampleRate / 1000000;
}
}
}
} catch (...) {
std::unique_lock<std::mutex> lock(instance->mtx);
*stop = true;
lock.unlock();
instance->cv.notify_one();
instance->cv.notify_all();
}
}
2 changes: 2 additions & 0 deletions transmitter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "wave_reader.hpp"
#include <condition_variable>
#include <thread>

class ClockOutput;

Expand All @@ -54,6 +55,7 @@ class Transmitter
static void TransmitterThread(Transmitter *instance, ClockOutput *output, unsigned sampleRate, unsigned clockDivisor, unsigned divisorRange, unsigned *sampleOffset, std::vector<Sample> *samples, bool *stop);

std::condition_variable cv;
std::thread txThread;
ClockOutput *output;
std::mutex mtx;
bool enable;
Expand Down
11 changes: 10 additions & 1 deletion wave_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ std::vector<uint8_t> WaveReader::ReadData(unsigned bytesToRead, bool headerBytes
unsigned bytesRead = 0;
std::vector<uint8_t> data;
data.resize(bytesToRead);
timeval timeout = {
.tv_sec = 1,
};
fd_set fds;
while (bytesRead < bytesToRead) {
{
std::lock_guard<std::mutex> lock(mtx);
Expand All @@ -191,7 +195,12 @@ std::vector<uint8_t> WaveReader::ReadData(unsigned bytesToRead, bool headerBytes
data.resize(bytesRead);
break;
} else {
std::this_thread::sleep_for(std::chrono::microseconds(1));
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &timeout);
if (FD_ISSET(STDIN_FILENO, &fds)) {
FD_CLR(STDIN_FILENO, &fds);
}
}
}
}
Expand Down

0 comments on commit ddfcf6a

Please sign in to comment.