Author Topic: Analog ISR for audio input  (Read 3407 times)

DrYerzinia

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Analog ISR for audio input
« on: July 23, 2014, 02:14:25 PM »
I need to be able to read in analog data at a sample rate of ~11025 Hz with a consistent interval and get the conversion in an ISR.  My main application loop can't sit around waiting for the analog conversion the regular Arduino way cause its running a expensive signal processing routine.  I'm reading through the nRF51822 data sheets and the source files for the RFduino trying to figure out how to tie into the Analog conversion ISR and set it up for 11025 Hz sample rate but its a lot to work through so if anyone knows how to set it up it would be much appreciated.  If the ADC dosen't do the timing itself which timers would be available for regularly starting the conversion, and how would you set up the end of conversion ISR.
As of right now I see the definitions for the ADC and timer in nrf51.h but I don't see what to name there respective ISR functions.

laputa

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #1 on: July 24, 2014, 09:17:49 AM »
Looking for same info, any luck?

DrYerzinia

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #2 on: July 24, 2014, 01:25:05 PM »
Some luck, spent most of last night tunning signal processing algorithm to get it under 62 uS per sample.
After reading the data sheet I saw that there is no continuous mode for the ADC so you have to use a timer.  The bluetooth stack uses timer0 and I found this thread about how to use the timer:
http://forum.rfduino.com/index.php?topic=155.msg1299#msg1299

Used this code to get a timer to fire at 11025 Hz.  Checked GPIO3 with osciliscope and it was changing at 11025Hz.  Next step for me is setting up the ADC interrupt and having it send data via UART make sure the sound is comming in right.  Ill post that code here when I get it going.
Code: [Select]

bool dir = false;

void TIMER2_Interrupt(void){
  if(NRF_TIMER2->EVENTS_COMPARE[0] != 0){

    if(dir)
      NRF_GPIO->OUTCLR = (1 << 3);
    else
      NRF_GPIO->OUTSET = (1 << 3);

    dir = !dir;

    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
  }
}

void TIMER2_Setup(void){

  NRF_TIMER2->TASKS_STOP = 1; // Stop timer
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
  NRF_TIMER2->PRESCALER = 3; // 125ns resolution
  NRF_TIMER2->TASKS_CLEAR = 1; // Clear timer
  NRF_TIMER2->CC[0] = 726; // 726 ticks * 125ns = ~11025 Hz
  NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER2->TASKS_START = 1; // Start TIMER

}

void setup() {

  Serial.begin(230400);

  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);

  TIMER2_Setup();

}

void loop() {

  // Nothing

}

laputa

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #3 on: July 24, 2014, 02:10:13 PM »
I found this PPI example. I think there are some resource conflicts but it was helpful in understanding the CPU.


/*
* This example enables the RTC with a TICK frequency of 10Hz. Each RTC TICK triggers
* ADC conversion through a PPI channel. The supply voltage for the chip is sampled
* with the ADC. To change the ADC output, adjust the Supply voltage for the nRF6310
* motherboard in nRFgo Studio. */

#include <stdbool.h>#include "nrf.h"
#include "nrf_delay.h"#include "nrf_gpio.h"
#define GPIO_TOGGLE_TICK_EVENT    (8)                     
/*!< Pin number to toggle when there is a tick event in RTC */

#define LFCLK_FREQUENCY           (32768UL)                 
/*!< LFCLK frequency in Hertz, constant */
#define RTC_FREQUENCY             (10UL)                   
/*!< required RTC working clock RTC_FREQUENCY Hertz. Changable */
#define COUNTER_PRESCALER         ((LFCLK_FREQUENCY/RTC_FREQUENCY) - 1)
/* f = LFCLK/(prescaler + 1) */


/** Configures port 1 as output */
static void gpio_config(void)
     {  nrf_gpio_range_cfg_output(8, 15);
      nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, 0);
      }


/** Configures and starts the low frequency 32kHz clock (required to operate the RTC) */
static void lfclk_config(void)
   {
  NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
  NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
  NRF_CLOCK->TASKS_LFCLKSTART = 1;

  // Wait for the low frequency clock to start 
  while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}
      NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
  }


/** Configures and starts RTC */
static void rtc_config(void)
    { 
        NRF_RTC0->PRESCALER = COUNTER_PRESCALER;            // Set prescaler to a TICK of RTC_FREQUENCY 
        NRF_RTC0->EVTENSET = RTC_EVTENSET_TICK_Msk;       // Enable TICK event
        NRF_RTC0->TASKS_START = 1;                                      // Start RTC0
      }


/** Configures and enables a PPI channel */
static void ppi_init(void)
   {  // Configure PPI channel 0 to start ADC task 
      NRF_PPI->CH[0].EEP = (uint32_t)&NRF_RTC0->EVENTS_TICK;
      NRF_PPI->CH[0].TEP = (uint32_t)&NRF_ADC->TASKS_START;       // Enable PPI channel 0 
      NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos);
    }

/** Configures and enables the ADC */
void ADC_init(void)
              {
   /* Enable interrupt on ADC sample ready event*/
   NRF_ADC->INTENSET = ADC_INTENSET_END_Msk;
   NVIC_EnableIRQ(ADC_IRQn);
               /* Configure ADC - set reference input source to internal 1.2V bandgap */
   NRF_ADC->CONFIG = (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos);
   /* Configure ADC - set input source to VDD/3 */
   NRF_ADC->CONFIG |= (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos);
   /* Configure ADC - select 8 bit resolution */
   NRF_ADC->CONFIG |= (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos);
   /* Enable ADC*/   
               NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
               }


 /* Interrupt handler for ADC data ready event */
 void ADC_IRQHandler(void){
   /* Clear dataready event */
               NRF_ADC->EVENTS_END = 0;
               /* Write ADC result to port 1 */
    nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, NRF_ADC->RESULT);     //Use the STOP task to save current. Workaround for PAN_028 rev1.2 anomaly 1. 
              NRF_ADC->TASKS_STOP = 1;
        }




Order of call was as follows:

  gpio_config();
  lfclk_config();
  rtc_config();
  ppi_init();
  ADC_init(); 
« Last Edit: July 24, 2014, 02:21:08 PM by laputa »

DrYerzinia

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #4 on: August 07, 2014, 11:27:04 PM »
Well I've concluded this can't be done while BLE is running because the interrupts won't fire for 5+ ms.  So istead im using a 1.12$ pic controller as ADC and it buffers audio samples which are retrived over SPI and it works great.  Still using the arduinos adc for reading battery levels and that works fine.

fdrg

  • RFduino Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #5 on: August 22, 2014, 09:51:06 AM »
Hello,

I was browsing the forum message looking both anyone using the UART at 230400 and noticed that DrYerzinia's code used this speed, did it work?
I think the chip UART does support this speed

Thank you!

mkay

  • RFduino Team
  • *****
  • Posts: 405
  • Karma: +15/-0
    • View Profile
Re: Analog ISR for audio input
« Reply #6 on: September 08, 2014, 03:19:25 PM »
Hi fdrg, the variant.cpp file in the library has a list of all the available baud rates. Yes 230,400 is one of them.