// nrf51_audio_rx.pde // Sample sketch for nRF51822 and RadioHead // // Plays audio samples received in the radio receiver // through a MCP4725 DAC such as on a SparkFun I2C DAC Breakout - MCP4725 (BOB-12918) // works with matching transmitter (see nrf51_audio_tx.pde) // Works with RedBear nRF51822 board. // See examples/nrf51_audiotx/nrf51_audio.pdf for connection details #include #include #include #include #include // Number of samples per second to play at. // Should match SAMPLE_RATE in nrf51_audio_tx // The limiting factor is the time it takes to output a new sample through the DAC #define SAMPLE_RATE 5000 // Number of 8 bit samples per packet // Should equal or exceed the PACKET_SIZE in nrf51_audio_tx #define MAX_PACKET_SIZE 255 // Singleton instance of the radio driver RH_NRF51 driver; void setup() { delay(1000); Serial.begin(9600); while (!Serial) ; // wait for serial port to connect. if (!driver.init()) Serial.println("init failed"); // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm // Set up TIMER // Use TIMER0 // Timer freq before prescaling is 16MHz (VARIANT_MCK) // We set up a 32 bit timer that restarts every 100us and outputs a new sample NRF_TIMER0->PRESCALER = 0 << TIMER_PRESCALER_PRESCALER_Pos; NRF_TIMER0->MODE = TIMER_MODE_MODE_Timer << TIMER_BITMODE_BITMODE_Pos; NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos; NRF_TIMER0->CC[0] = VARIANT_MCK / SAMPLE_RATE; // Counts per cycle // When timer count expires, its cleared and restarts NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; NRF_TIMER0->TASKS_START = 1; // Enable an interrupt when timer completes NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk; // Enable the TIMER0 interrupt, and set the priority // TIMER0_IRQHandler() will be called after each sample is available NVIC_SetPriority(TIMER0_IRQn, 1); NVIC_EnableIRQ(TIMER0_IRQn); // Initialise comms with the I2C DAC as fast as we can // Shame the 51822 does not suport the high speed I2C mode that the DAC does Wire.begin(TWI_SCL, TWI_SDA, TWI_FREQUENCY_400K); } volatile uint32_t count = 0; uint8_t buffer_length = 0; uint8_t buffer[MAX_PACKET_SIZE]; uint16_t buffer_play_index = 0; // Write this sample to analog out void analog_out(uint8_t val) { // This takes about 120usecs, which // is the limiting factor for our sample rate of 5kHz // Writes to MCP4725 DAC over I2C using the Wire library Wire.beginTransmission(0x60); // 7 bit addressing Wire.write((val >> 4) & 0x0f); Wire.write((val << 4) & 0xf0); Wire.endTransmission(); } // Called by timer interrupt // Output the next available sample void output_next_sample() { if (buffer_play_index < buffer_length) { analog_out(buffer[buffer_play_index++]); } } void loop() { // Look for a new packet of samples if (driver.available()) { // expect one of these every 40ms = 25Hz // This takes about 400us: buffer_length = sizeof(buffer); driver.recv(buffer, &buffer_length); buffer_play_index = 0; // Trigger the interrupt playing of this buffer from the start } } // This interrupt handler called when the timer interrupt fires // Time to output the next sample void TIMER0_IRQHandler(void) { // It is vitally important that analog output completes before // the next interrupt becomes due! output_next_sample(); NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the COMPARE[0] event and the interrupt }