Geavanceerde XBee Walkie-Talkie met Arduino, DAC en Audio Versterkers
Onderdelen en benodigdheden
| Goldilocks Analogue (prototype, functionaliteit te recreëren met MCP4822 DAC, Microfoonversterker, Hoofdtelefoonversterker, en Arduino Uno) | 1 |
| MAX9744 (hoofdtelefoonversterker) | 1 |
| MAX9814 (microfoonversterker) | 1 |
| MCP4921 DAC | 1 |
| Arduino UNO | 1 |
| Arduino Wireless Shield (XBee) | 1 |
Over dit project
Ik bouw een geavanceerde Arduino kloon gebaseerd op de AVR ATmega1284p MCU met speciale features waaronder een 12-bit DAC MCP4822, hoofdtelefoonversterker, 2x SPI geheugen (SRAM, EEPROM), en een SD kaart. Er zijn veel real-world toepassingen voor analoge outputs, maar omdat het Arduino platform geen geïntegreerde DAC capaciteit heeft, zijn er weinig gepubliceerde toepassingen voor analoge signalen. Een walkie-talkie is een voorbeeld van het combineren van digitaal en analoog om een simpel maar nuttig project te maken.
De walkie-talkie functionaliteit is eigenlijk maar een paar regels code, maar bouwt op een fundament van analoge input (sampling), analoge output op de SPI bus naar de MCP4822 DAC, sample timing routines, en het XBee digitale radioplatform. Laten we van bovenaf beginnen en dieper graven.
XBee Radio
Ik gebruik XBee Pro S2B radio's, geconfigureerd voor point-to-point communicatie. Er moet één radio als Coordinator en de andere als Router geconfigureerd zijn. Configuratie handleidingen zijn online te vinden.
Ik heb de radio's geconfigureerd om de maximale inter-character wachttijd te wachten voordat een pakket wordt verstuurd, wat betekent dat pakketten alleen worden verstuurd wanneer ze vol zitten (84 bytes). Dit maximaliseert de radio doorvoersnelheid. Ruwe throughput is 250 kbit/s, maar de daadwerkelijke gebruikersdatarate is beperkt tot ongeveer 32 kbit/s. Dit heeft impact op de sample rate en dus de spraakkwaliteit die verzonden kan worden.
Met 8-bit samples heb ik gevonden dat ongeveer 3 kHz sampling zoveel data genereert als er zonder compressie verzonden kan worden. Compressie laat ik voor een ander project.
De XBee radio's zijn in AT mode geconfigureerd, wat fungeert als een transparante seriële pipe tussen de twee eindpunten. Dit is de simpelste manier om twee apparaten via digitale radio te verbinden en maakte eenvoudige testen met draad mogelijk voordat ik me zorgen maakte over het radioplatform.
In de logica analyser trace zien we XBee datapakketten aankomen op de (paarse) Rx lijn van de seriële poort. Ontvangen pakketdata wordt opgeslagen in een ringbuffer en op constante snelheid afgespeeld. Ik toestaan tot 255 bytes in de ontvangstringbuffer, voldoende omdat de XBee pakketgrootte 84 bytes is.
De samples om te verzenden worden op de (blauwe) Tx lijn uitgezonden, min of meer elke sampleperiode, hoewel ze gebufferd worden voor transmissie. De XBee bufferd deze bytes voor maximaal 0xFF inter-symbol periodes (configureerbaar), en stuurt alleen een pakket naar het andere eindpunt als het een vol pakket heeft.
Sample Rate
Kijkend naar het bitbudget voor de transmissielink, moeten we berekenen hoeveel data verzonden kan worden zonder de XBee te overbelasten en sample loss te veroorzaken. Zonder compressie hebben we 8-bit samples × 3.000 Hz = 24 kbit/s te verzenden. Dit werkt goed. Ik probeerde 4 kHz sampling, maar dat is te dicht bij het theoretische maximum en werkt niet effectief.
In de logica analyser zien we de aankomst van een pakket bytes beginnend met 0x7E en 0x7C op de Rx lijn. Zowel de microfoonversterker als de DAC output zijn gebias rond 0x7F(FF), dus we kunnen aflezen dat de gesignaleerde niveaus hier erg laag zijn. De getoonde sample rate is 3.000 Hz.
Sample Verwerking
Ik heb een "ping" op één output gezet om vast te leggen wanneer de sampling interrupt verwerkt wordt (geel). We zien dat de tijd in de interrupt verwerking erg klein is ten opzichte van de totale beschikbare tijd. Mogelijk zou datacompressie geïmplementeerd kunnen worden.
Tijdens de sampling interrupt zijn er twee hoofdactiviteiten: audio output genereren door een sample op de DAC te plaatsen, en de ADC lezen om een audio sample te vangen en naar de USART buffer te sturen.
Dit wordt gedaan door de audioCodec_dsp functie, aangeroepen vanuit een timer interrupt.
Ik gebruik de AVR 8-bit Timer0 om regelmatige sample intervallen te genereren via een interrupt. Door een MCU FCPU frequentie te gebruiken die een binaire veelvoud is van standaard audio frequenties, kunnen we nauwkeurige reproduktie sample rates genereren met alleen de 8-bit timer met een klok prescaler van 64. Voor oneven audio frequenties zoals 44.100 Hz kan de 16-bit Timer1 gebruikt worden voor voldoende nauwkeurigheid zonder klok prescaler.
De ATmega1284p ADC staat in free-run mode, geschaald naar 192 kHz. Dit is dicht bij de maximum acquisitiesnelheid gedocumenteerd voor de ATmega ADC, maar nog binnen specificatie voor 8-bit samples.
Deze interrupt neemt 14 µs in beslag, heel kort ten opzichte van de 333 µs per sampleperiode. Dit geeft ruimte voor andere verwerking, zoals een user interface of verdere audio verwerking.
SPI Transactie
Op het laagste detailniveau zien we de daadwerkelijke SPI transactie om de binnenkomende sample naar de MCP4822 DAC te sturen.
Deze applicatie is gebouwd op de Goldilocks Analogue Prototype 2 die de standaard SPI bus gebruikt. Later prototypes gebruiken de Master SPI Mode op USART 1 van de ATmega1284p, wat de SPI transactie iets versnelt door double buffering en de normale SPI bus vrijmaakt voor gelijktijdig lezen/schrijven naar SD kaart of SPI geheugen voor audio streaming. In de walkie-talkie applicatie is er geen behoefte aan audio opname, dus geen nadeel aan het gebruik van de oudere prototypes en de standaard SPI bus.
Afsluiting
Met een paar bestaande tools en een paar regels code is het mogelijk om snel een digitaal versleutelde walkie-talkie te bouwen, capabel van communiceren (begrijpelijk, maar niet hoge kwaliteit) stem. En er luisteren geen CB truckers meer mee naar familiegesprekken.
Dit was een test van het toevoegen van microfooninput gebaseerd op de MAX9814 aan de Goldilocks Analogue. Ik zal Prototype 3 herzien en een microfoonversterkingscircuit toevoegen voor toepassingen die audio input nodig hebben, zoals deze walkie-talkie, stemveranderaars, of vocale controle muziek synthesizers.
Ik draai de ATmega1284p apparaten ook op de verhoogde frequentie van 24,576 MHz, boven de standaard 20 MHz. Deze specifieke frequentie staat heel nauwkeurige reproductie van audio samples toe van 48 kHz helemaal naar beneden tot 4 kHz (of zelfs 1.500 Hz). De extra MCU klokcycli per sampleperiode zijn welkom bij het genereren van gesyntheserde muziek.
Code zoals gebruikelijk op SourceForge AVR freeRTOS. Ook een shout-out naar Shuyang bij SeeedStudio wiens OPL geweldig is en bron is van veel componenten en PCB's.
Code
audioCodec_dsp functie (C/C++)
void audioCodec_dsp(uint16_t * ch_A, uint16_t * ch_B) {
int16_t xn;
uint8_t cn;
/*----- Audio Rx -----*/
if(ringBuffer_IsEmpty((ringBuffer_t*) &(xSerialPort.xRxedChars))) {
cn = 0x80 ^ 0x55; // A-Law genulld signaal op output
} else if (ringBuffer_GetCount(&(xSerialPort.xRxedChars)) > (portSERIAL_BUFFER_RX >> 1)) {
cn = ringBuffer_Pop((ringBuffer_t*) &(xSerialPort.xRxedChars));
cn = ringBuffer_Pop((ringBuffer_t*) &(xSerialPort.xRxedChars)); // twee samples poppen om in te halen
} else {
cn = ringBuffer_Pop((ringBuffer_t*) &(xSerialPort.xRxedChars));
}
alaw_expand1(&cn, &xn); // A-Law decompressie
*ch_A = *ch_B = (uint16_t)(xn + 0x7fff); // signaal naar positieve waarden, output op A & B kanaal
/*----- Audio Tx -----*/
AudioCodec_ADC(&mod7_value.u16); // sample is 10bits left justified
xn = mod7_value.u16 - 0x7fe0; // centreer sample op 0
IIRFilter(&tx_filter, &xn); // filter verzonden sample
alaw_compress1(&xn, &cn); // comprimeer met A-Law
xSerialPutChar(&xSerialPort, cn); // verstuur sample
}
Timer0 Interrupt Service Routine (C/C++)
ISR(TIMER0_COMPA_vect) __attribute__ ((hot, flatten));
ISR(TIMER0_COMPA_vect) {
#if defined(DEBUG_PING)
PORTD |= _BV(PORTD7); // Ping IO lijn voor debugging
#endif
// MCP4822 data transfer routine - eerste voor regelmaat (verminderde jitter)
DAC_out(ch_A_ptr, ch_B_ptr);
// Audio verwerkingsroutine
if (audioHandler != NULL)
audioHandler(ch_A_ptr, ch_B_ptr);
#if defined(DEBUG_PING)
PORTD &= ~_BV(PORTD7);
#endif
}
DAC_out functie (C/C++)
void DAC_out(const uint16_t * ch_A, const uint16_t * ch_B) {
DAC_command_t write;
if (ch_A != NULL) {
write.value.u16 = (*ch_A) >> 4;
write.value.u8[1] |= CH_A_OUT;
} else {
write.value.u8[1] = CH_A_OFF;
}
SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC; // SS laag voor selectie
SPDR = write.value.u8[1];
while (!(SPSR & _BV(SPIF)));
SPDR = write.value.u8[0];
if (ch_B != NULL) {
write.value.u16 = (*ch_B) >> 4;
write.value.u8[1] |= CH_B_OUT;
} else {
write.value.u8[1] = CH_B_OFF;
}
while (!(SPSR & _BV(SPIF)));
SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC; // SS hoog om te deselecteren en latchen
SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC;
SPDR = write.value.u8[1];
while (!(SPSR & _BV(SPIF)));
SPDR = write.value.u8[0];
while (!(SPSR & _BV(SPIF)));
SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC;
}
AVR freeRTOS repository op SourceForge: https://sourceforge.net/projects/avrfreertos/
Schema's
Let op: Het schema is niet 100% correct omdat Fritzing geen MCP4822 DAC (SPI) had, maar een MCP4725 (I2C). Ook is het maar in één richting getekend (behalve Rx/Tx die miteinander verbonden zijn). De XBee bordjes vervangen simpelweg de twee draden die Rx en Tx verbinden. Elke radio set die voldoende data kan dragen zou werken.
Schema voor DAC output en hoofdtelefoonversterker. Microfooninputversterker wordt toegevoegd in prototype 4.
Productieproces
- Belangrijke Overwegingen voor Hoog‑Volume Zweedse Bewerking
- CNC Prototyping Gids: Precisie, Snelheid en Kosten‑Effectieve Productie
- Expert Asfabricatie: Precisieprocessen & Custom Oplossingen
- Roestvrij Staal Passiveren: Corrosiebestendigheid & Prestaties Verbeteren
- Analoge Sensoren Meten op de Raspberry Pi met een Enkele GPIO-pin
- Een MCP3008 ADC gebruiken om analoge sensoren met Raspberry Pi uit te lezen
- Hoogprecieze golfvormgeneratie met een DAC-gebaseerde custom PCB
- Slimme Irrigatiecontroller met Windows 10 IoT, Raspberry Pi en XBee Vocht-sensoren
- Aangepaste Visuals op je Oscilloscoop Maken met een R-2R DAC
- Geavanceerde afgeschermde kabels voor signaalcircuits: praktische aansluittechnieken (Deel 2)
- Waarom analoge metingen plantprestaties drijven