Merge pull request #70 from markondej/bandwidth_param

Allow custom bandwidth settings
pull/74/head
Marcin Kondej 2019-01-08 14:41:21 +01:00 zatwierdzone przez GitHub
commit c78045961a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 40 dodań i 34 usunięć

Wyświetl plik

@ -1,8 +1,9 @@
# fm_transmitter
Use Raspberry Pi as FM transmitter. Works on any Raspberry Pi board.
Use Raspberry Pi as FM transmitter. Works on every Raspberry Pi board.
This project uses the general clock output to produce frequency modulated radio communication. It is based on idea originaly presented by [Oliver Mattos and Oskar Weigl](http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter) on [PiFM project](http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter).
Just get an FM receiver and connect 20 - 40 cm plain wire to GPIO4 (PIN 7 on Raspberry Pi GPIO header) to act as an antena.
## How to use it
To use this project You will have to build it. First, clone this repository, then use "make" command as shown below:
```
@ -17,11 +18,11 @@ sudo ./fm_transmitter -f 102.0 acoustic_guitar_duet.wav
Where:
* -f frequency - Specifies the frequency in MHz, 100.0 by default if not passed
* acoustic_guitar_duet.wav - Sample WAVE file, You can use your own
Other options:
* -d dma_channel - Specifies the used DMA channel (0 by default), pass 255 in order to disable DMA and use CPU
* -d dma_channel - Specifies DMA channel to be used (0 by default), type 255 to disable DMA transfer, CPU will be used instead
* -b bandwidth - Specifies the bandwidth in kHz, 100 by default
* -r - Loops the playback
After transmission has begun, simply tune an FM receiver to chosen frequency, You should hear the playback.
### Supported audio formats
You can transmitt uncompressed WAVE (.wav) files directly or read audio data from stdin, eg.:
```
@ -38,14 +39,12 @@ In order to use a USB microphone input use arecord command, eg.:
arecord -D hw:1,0 -c1 -d 0 -r 22050 -f S16_LE | sudo ./fm_transmitter -f 100.6 -
```
In case of performance drop down use ```plughw:1,0``` instead of ```hw:1,0```.
## Legal note
Please keep in mind that transmitting on certain frequencies without special permissions may be illegal in your country.
## New features
* DMA peripheral support
* works on any Raspberry Pi model
* Allows custom frequency and bandwidth settings
* works on every Raspberry Pi model
* reads mono and stereo files
* reads data from stdin
Included sample audio was created by [graham_makes](https://freesound.org/people/graham_makes/sounds/449409/) and published on [freesound.org](https://freesound.org/)

Wyświetl plik

@ -54,13 +54,14 @@ void sigIntHandler(int sigNum)
int main(int argc, char** argv)
{
double frequency = 100.0;
double bandwidth = 100.0;
unsigned short dmaChannel = 0;
bool loop = false;
string filename;
bool showUsage = true;
int opt, filesOffset;
while ((opt = getopt(argc, argv, "rf:d:v")) != -1) {
while ((opt = getopt(argc, argv, "rf:d:b:v")) != -1) {
switch (opt) {
case 'r':
loop = true;
@ -71,6 +72,9 @@ int main(int argc, char** argv)
case 'd':
dmaChannel = ::atof(optarg);
break;
case 'b':
bandwidth = ::atof(optarg);
break;
case 'v':
cout << EXECUTABLE << " version: " << VERSION << endl;
return 0;
@ -81,11 +85,12 @@ int main(int argc, char** argv)
showUsage = false;
}
if (showUsage) {
cout << "Usage: " << EXECUTABLE << " [-f <frequency>] [-d <dma_channel>] [-r] <file>" << endl;
cout << "Usage: " << EXECUTABLE << " [-f <frequency>] [-b <bandwidth>] [-d <dma_channel>] [-r] <file>" << endl;
return 0;
}
signal(SIGINT, sigIntHandler);
signal(SIGTSTP, sigIntHandler);
try {
transmitter = &Transmitter::getInstance();
@ -96,11 +101,13 @@ int main(int argc, char** argv)
}
WaveReader reader(filename != "-" ? filename : string(), play);
PCMWaveHeader header = reader.getHeader();
cout << "Broadcasting on " << frequency << " MHz with "
<< bandwidth << " kHz bandwidth" << endl;
cout << "Playing: " << reader.getFilename() << ", "
<< header.sampleRate << " Hz, "
<< header.bitsPerSample << " bits, "
<< ((header.channels > 0x01) ? "stereo" : "mono") << endl;
transmitter->play(reader, frequency, dmaChannel, optind < argc);
transmitter->play(reader, frequency, bandwidth, dmaChannel, optind < argc);
} while (play && (optind < argc));
} catch (exception &error) {
cout << "Error: " << error.what() << endl;

Wyświetl plik

@ -1,11 +1,11 @@
EXECUTABLE = fm_transmitter
VERSION = 0.9.1
FLAGS = -Wall -fexceptions -pthread -O3 -fpermissive -fno-strict-aliasing
FLAGS = -Wall -O3
LIBS = -lm
all: main.o mailbox.o error_reporter.o sample.o preemp.o wave_reader.o transmitter.o
g++ $(FLAGS) -L/opt/vc/lib -lm -lbcm_host -o $(EXECUTABLE) main.o mailbox.o sample.o preemp.o error_reporter.o wave_reader.o transmitter.o
g++ -L/opt/vc/lib -lm -lpthread -lbcm_host -o $(EXECUTABLE) main.o mailbox.o sample.o preemp.o error_reporter.o wave_reader.o transmitter.o
mailbox.o: mailbox.c mailbox.h
g++ $(FLAGS) -c mailbox.c
@ -23,7 +23,7 @@ wave_reader.o: wave_reader.cpp wave_reader.h
g++ $(FLAGS) -c wave_reader.cpp
transmitter.o: transmitter.cpp transmitter.h
g++ $(FLAGS) -I/opt/vc/include -c transmitter.cpp
g++ $(FLAGS) -fno-strict-aliasing -I/opt/vc/include -c transmitter.cpp
main.o: main.cpp
g++ $(FLAGS) -DVERSION=\"$(VERSION)\" -DEXECUTABLE=\"$(EXECUTABLE)\" -c main.cpp

Wyświetl plik

@ -178,7 +178,7 @@ unsigned Transmitter::getAddress(volatile void *object)
return (memSize) ? memAddress + ((unsigned)object - (unsigned)memAllocated) : 0x00000000;
}
void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaChannel, bool preserveCarrierOnExit)
void Transmitter::play(WaveReader &reader, double frequency, double bandwidth, unsigned char dmaChannel, bool preserveCarrierOnExit)
{
if (transmitting) {
throw ErrorReporter("Cannot play, transmitter already in use");
@ -195,7 +195,8 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
}
bool eof = samples->size() < bufferSize;
unsigned clockDivisor = (unsigned)((500 << 12) / frequency + 0.5);
unsigned clockDivisor = (unsigned)round((500 << 12) / frequency);
unsigned divisorRange = clockDivisor - (unsigned)round((500 << 12) / (frequency + 0.0005 * bandwidth));
bool isError = false;
string errorMessage;
@ -205,7 +206,7 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
throw ErrorReporter("DMA channel number out of range (0 - 15)");
}
if (!allocateMemory(sizeof(unsigned) * ((bufferSize << 1) + 1) + sizeof(DMAControllBlock) * (bufferSize << 1))) {
if (!allocateMemory(sizeof(unsigned) * ((2 * bufferSize) + 1) + sizeof(DMAControllBlock) * (2 * bufferSize))) {
delete samples;
throw ErrorReporter("Cannot allocate memory");
}
@ -245,14 +246,14 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
#endif
volatile DMAControllBlock *dmaCb = (DMAControllBlock *)memAllocated;
volatile unsigned *clkDiv = (unsigned *)memAllocated + ((sizeof(DMAControllBlock) / sizeof(unsigned)) << 1) * bufferSize;
volatile unsigned *pwmFifoData = (unsigned *)memAllocated + (((sizeof(DMAControllBlock) / sizeof(unsigned)) << 1) + 1) * bufferSize;
volatile unsigned *clkDiv = (unsigned *)memAllocated + 2 * (sizeof(DMAControllBlock) / sizeof(unsigned)) * bufferSize;
volatile unsigned *pwmFifoData = (unsigned *)memAllocated + 2 * ((sizeof(DMAControllBlock) / sizeof(unsigned)) + 1) * bufferSize;
for (i = 0; i < bufferSize; i++) {
value = (*samples)[i].getMonoValue();
#ifndef NO_PREEMP
value = preEmp.filter(value);
#endif
clkDiv[i] = (0x5A << 24) | (clockDivisor - (int)round(value * 16.0));
clkDiv[i] = (0x5A << 24) | (clockDivisor - (int)round(value * divisorRange));
dmaCb[cbIndex].transferInfo = (0x01 << 26) | (0x01 << 3);
dmaCb[cbIndex].srcAddress = getAddress(&clkDiv[i]);
dmaCb[cbIndex].dstAddress = PERIPHERALS_PHYS_BASE | (CLK0_BASE_OFFSET + 0x04);
@ -279,7 +280,7 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
dma->cbAddress = getAddress(dmaCb);
dma->ctlStatus = (0xFF << 16) | 0x01;
usleep(BUFFER_TIME >> 2);
usleep(BUFFER_TIME / 4);
try {
while (!eof && transmitting) {
@ -294,10 +295,10 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
#ifndef NO_PREEMP
value = preEmp.filter(value);
#endif
while (i == (((dma->cbAddress - getAddress(dmaCb)) / sizeof(DMAControllBlock)) >> 1)) {
while (i == ((dma->cbAddress - getAddress(dmaCb)) / (2 *sizeof(DMAControllBlock)))) {
usleep(1);
}
clkDiv[i] = (0x5A << 24) | (clockDivisor - (int)round(value * 16.0));
clkDiv[i] = (0x5A << 24) | (clockDivisor - (int)round(value * divisorRange));
cbIndex += 2;
}
delete samples;
@ -308,11 +309,8 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
isError = true;
}
if (eof || isError) {
dmaCb[cbIndex].nextCbAddress = 0x00;
} else {
dmaCb[(bufferSize - 1) << 1].nextCbAddress = 0x00;
}
cbIndex -= 2;
dmaCb[cbIndex].nextCbAddress = 0x00;
while (dma->cbAddress != 0x00) {
usleep(1);
}
@ -330,10 +328,11 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
unsigned sampleOffset = 0;
vector<Sample> *buffer = samples;
void *transmitterParams[4] = {
void *transmitterParams[5] = {
(void *)&buffer,
(void *)&sampleOffset,
(void *)&clockDivisor,
(void *)&divisorRange,
(void *)&header.sampleRate
};
@ -346,7 +345,7 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
throw ErrorReporter(oss.str());
}
usleep(BUFFER_TIME >> 1);
usleep(BUFFER_TIME / 2);
try {
while (!eof && transmitting) {
@ -361,7 +360,7 @@ void Transmitter::play(WaveReader &reader, double frequency, unsigned char dmaCh
eof = samples->size() < bufferSize;
buffer = samples;
}
usleep(BUFFER_TIME >> 1);
usleep(BUFFER_TIME / 2);
}
}
catch (ErrorReporter &error) {
@ -389,7 +388,8 @@ void *Transmitter::transmit(void *params)
vector<Sample> **buffer = (vector<Sample> **)((void **)params)[0];
unsigned *sampleOffset = (unsigned *)((void **)params)[1];
unsigned *clockDivisor = (unsigned *)((void **)params)[2];
unsigned *sampleRate = (unsigned *)((void **)params)[3];
unsigned *divisorRange = (unsigned *)((void **)params)[3];
unsigned *sampleRate = (unsigned *)((void **)params)[4];
unsigned offset, length, prevOffset;
vector<Sample> *samples = NULL;
@ -442,7 +442,7 @@ void *Transmitter::transmit(void *params)
#ifndef NO_PREEMP
value = preEmp.filter(value);
#endif
clk0->div = (0x5A << 24) | (*clockDivisor - (int)round(value * 16.0));
clk0->div = (0x5A << 24) | (*clockDivisor - (int)round(value * (*divisorRange)));
while (offset == prevOffset) {
usleep(1); // asm("nop");
current = *(unsigned long long *)&timer->low;

Wyświetl plik

@ -43,7 +43,7 @@ class Transmitter
public:
virtual ~Transmitter();
static Transmitter &getInstance();
void play(WaveReader &reader, double frequency, unsigned char dmaChannel, bool preserveCarrierOnExit);
void play(WaveReader &reader, double frequency, double bandwidth, unsigned char dmaChannel, bool preserveCarrierOnExit);
void stop();
private:
Transmitter();