Fixed ARM64 bug, when not using DMA

pull/189/head
Marcin Kondej 2023-08-14 02:11:23 +02:00
rodzic 019f39c220
commit ddfcf6a53c
4 zmienionych plików z 88 dodań i 86 usunięć

Wyświetl plik

@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include "mailbox.h" #include "mailbox.hpp"
#define PAGE_SIZE (4*1024) #define PAGE_SIZE (4*1024)

Wyświetl plik

@ -51,7 +51,6 @@
#define BCM2711_PLLD_FREQ 750 #define BCM2711_PLLD_FREQ 750
#define GPIO_BASE_OFFSET 0x00200000 #define GPIO_BASE_OFFSET 0x00200000
#define TIMER_BASE_OFFSET 0x00003000
#define CLK0_BASE_OFFSET 0x00101070 #define CLK0_BASE_OFFSET 0x00101070
#define CLK1_BASE_OFFSET 0x00101078 #define CLK1_BASE_OFFSET 0x00101078
@ -100,16 +99,6 @@
#define BUFFER_TIME 1000000 #define BUFFER_TIME 1000000
#define PAGE_SIZE 4096 #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 { struct ClockRegisters {
uint32_t ctl; uint32_t ctl;
uint32_t div; uint32_t div;
@ -359,6 +348,10 @@ Transmitter::Transmitter()
} }
Transmitter::~Transmitter() { Transmitter::~Transmitter() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&]() -> bool {
return !txThread.joinable() && !enable;
});
if (output != nullptr) { if (output != nullptr) {
delete output; delete output;
} }
@ -386,6 +379,11 @@ void Transmitter::Transmit(WaveReader &reader, float frequency, float bandwidth,
delete output; delete output;
output = nullptr; output = nullptr;
} }
{
std::lock_guard<std::mutex> lock(mtx);
enable = false;
}
cv.notify_all();
}; };
try { try {
if (dmaChannel != 0xff) { if (dmaChannel != 0xff) {
@ -408,66 +406,6 @@ void Transmitter::Stop()
cv.notify_all(); 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) void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange, unsigned dmaChannel)
{ {
if (dmaChannel > 15) { if (dmaChannel > 15) {
@ -526,8 +464,6 @@ void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsign
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
samples.clear(); samples.clear();
std::lock_guard<std::mutex> lock(mtx);
enable = false;
}; };
try { try {
while (!eof) { while (!eof) {
@ -559,14 +495,69 @@ void Transmitter::TransmitViaDma(WaveReader &reader, ClockOutput &output, unsign
finally(); finally();
} }
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 {
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();
}
void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output, unsigned sampleRate, unsigned clockDivisor, unsigned divisorRange, unsigned *sampleOffset, std::vector<Sample> *samples, bool *stop) void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output, unsigned sampleRate, unsigned clockDivisor, unsigned divisorRange, unsigned *sampleOffset, std::vector<Sample> *samples, bool *stop)
{ {
try { try {
Peripherals &peripherals = Peripherals::GetInstance(); auto playbackStart = std::chrono::system_clock::now();
std::chrono::system_clock::time_point current, start;
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;
while (true) { while (true) {
std::vector<Sample> loadedSamples; std::vector<Sample> loadedSamples;
@ -578,11 +569,11 @@ void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output,
if (*stop) { if (*stop) {
break; break;
} }
start = current = *(reinterpret_cast<volatile uint64_t *>(&timer->low)); start = current = std::chrono::system_clock::now();
*sampleOffset = (current - playbackStart) * sampleRate / 1000000; *sampleOffset = std::chrono::duration_cast<std::chrono::microseconds>(current - playbackStart).count() * sampleRate / 1000000;
loadedSamples = std::move(*samples); loadedSamples = std::move(*samples);
lock.unlock(); lock.unlock();
instance->cv.notify_one(); instance->cv.notify_all();
unsigned offset = 0; unsigned offset = 0;
@ -595,8 +586,8 @@ void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output,
instance->output->SetDivisor(clockDivisor - static_cast<int>(round(value * divisorRange))); instance->output->SetDivisor(clockDivisor - static_cast<int>(round(value * divisorRange)));
while (offset == prevOffset) { while (offset == prevOffset) {
std::this_thread::yield(); // asm("nop"); std::this_thread::yield(); // asm("nop");
current = *(reinterpret_cast<volatile uint64_t *>(&timer->low));; current = std::chrono::system_clock::now();
offset = (current - start) * sampleRate / 1000000; offset = std::chrono::duration_cast<std::chrono::microseconds>(current - start).count() * sampleRate / 1000000;
} }
} }
} }
@ -604,6 +595,6 @@ void Transmitter::TransmitterThread(Transmitter *instance, ClockOutput *output,
std::unique_lock<std::mutex> lock(instance->mtx); std::unique_lock<std::mutex> lock(instance->mtx);
*stop = true; *stop = true;
lock.unlock(); lock.unlock();
instance->cv.notify_one(); instance->cv.notify_all();
} }
} }

Wyświetl plik

@ -35,6 +35,7 @@
#include "wave_reader.hpp" #include "wave_reader.hpp"
#include <condition_variable> #include <condition_variable>
#include <thread>
class ClockOutput; class ClockOutput;
@ -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); 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::condition_variable cv;
std::thread txThread;
ClockOutput *output; ClockOutput *output;
std::mutex mtx; std::mutex mtx;
bool enable; bool enable;

Wyświetl plik

@ -171,6 +171,10 @@ std::vector<uint8_t> WaveReader::ReadData(unsigned bytesToRead, bool headerBytes
unsigned bytesRead = 0; unsigned bytesRead = 0;
std::vector<uint8_t> data; std::vector<uint8_t> data;
data.resize(bytesToRead); data.resize(bytesToRead);
timeval timeout = {
.tv_sec = 1,
};
fd_set fds;
while (bytesRead < bytesToRead) { while (bytesRead < bytesToRead) {
{ {
std::lock_guard<std::mutex> lock(mtx); std::lock_guard<std::mutex> lock(mtx);
@ -191,7 +195,12 @@ std::vector<uint8_t> WaveReader::ReadData(unsigned bytesToRead, bool headerBytes
data.resize(bytesRead); data.resize(bytesRead);
break; break;
} else { } 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);
}
} }
} }
} }