Using with Arduino Mega 2560

Re: Using with Arduino Mega 2560

Postby scott2 » Fri Nov 02, 2012 9:20 pm

Thanks! I will try the fixes when I get back to the lab this weekend.


So w.r.t to both of your posts, SS can't just be an arbitrary* digital pin? I see on the ATMEGA2560 datasheet that PORTB0 is for toggling the default SS, but - let's say I were to still use pin D10 instead of D53 - I could using digitalWrite() instead of calling the AVR code here, right?


Last, this may be jumping the gun, but once I get this working on the mega, I'm going to try to port the driver for PIC to use with the Chipkit Max32 (http://www.digilentinc.com/Data/Product ... x32_rm.pdf) - which of course I purchased RIGHT before the Due was released x_x Given that can you help explain the following syntax?

Code: Select all
asm volatile ("out %0, %A1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );


I get that
Code: Select all
asm
is for assembly calls, but I'm having trouble googling for how to read and understand the syntax you have after that. And I guess, more generally, what's the general cross-platform procedure for writing the data transfer function? I've tried comparing your code between the AVR and ARM libraries, but am having generally a tough time figuring out what's actually being done. Maybe I need to delve into the codec chip datasheet...
scott2
 
Posts: 15
Joined: Thu Sep 27, 2012 5:48 pm

Re: Using with Arduino Mega 2560

Postby guest » Sat Nov 03, 2012 3:07 am

SS can be almost any pin. it needs to be on PORT A, B, C, D, E, F, or G. this is because these ports can be toggled with the CBI and SBI commands, whereas the remainder need to be written to as a whole register. so if you pick a different pin, just make sure its on one of those ports, and use its correct number in the SPI setup function, and then put the right port letter and number in the data transfer function. you need to use the AVR assembly code in the data transfer function to ensure that it uses the SBI and CBI commands, as the timing is crucial. generally the C code compiles down to them, but i didnt want to take any chances. the arduino code actually does an entire function call to set pins, so it takes forever.

inline assembly is one of the most confusing languages ive ever had to deal with, which isnt saying too much, considering i havent used that many languages. but anyways, its putting the data from the function call out on to the SPI data transfer register, to send it to the codec.

Code: Select all
asm volatile ("out %0, %A1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );
out = set data from second operand to first
%0 is first operand
%A1 is first byte of second operand


the difficulty with porting it to the pic32 is getting the low level SS to toggle at the right time. you will need low level access to the port, and figure out how many wait states to put in. if you look at the code for the Maple, you will see a fair bit of NOPs to get the timing just right.
guest
Site Admin
 
Posts: 449
Joined: Thu May 20, 2010 11:58 pm

Re: Using with Arduino Mega 2560

Postby scott2 » Sun Nov 04, 2012 6:17 pm

Cheers, guest.


Still no luck it seems, unfortunately. I've quadruple-checked all of my connections, and also delved into the atmega2560 vs atmega328P datasheets to verify that all of the register settings are consistent between timer1 vs timer 5 (they are). Unfortunately, I don't have direct access to an oscope, but should be able to track one down in to use in one of our labs later this week.

My current pin mappings are as follows - anything not listed is not connected:
Code: Select all
3.3V Mega > 3.3V Shield (/Uno equiv pin)
5V Mega > 5V Shield (/Uno equiv pin)
GND (above Vin) Mega > GND (above Vin) Shield (/Uno equiv pin) - I don't have both grounds tied
A0 Mega > A0 Shield/Uno
A1 Mega > A1 Shield/Uno
20/SDA Mega > A4/SDA Shield/Uno
21/SCL Mega > A5/SCL Shield/Uno
D53/SS Mega > D10/SS Shield/Uno
D51/MOSI Mega > D11/MOSI Shield/Uno
D50/MISO Mega > D12/MISO Shield/Uno
D52/SCK Mega > D13/SCK Shield/Uno


Updated all the changes you suggested, and below is the code:

Code: Select all
/*
microphone.pde
guest openmusiclabs 8.17.11
this program takes input from the MIC pins on the codecshield.
NOTE: you will have to do a few solder joints to connect
your microphone, a description of this is on the wiki:
http://wiki.openmusiclabs.com/wiki/CodecShieldMicMod
this can also be used with low level instruments, like guitars,
to boost the volume on the input.
*/


// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1Khz
#define ADCS 0 // no ADCs are being used
#define MUTEMIC 0 // turn off the mute on the microphone
#define INSEL 1 // select the microphone input
#define MICBOOST 1 // enables the microphone +10dB amp
                   // set this to 0 if its too loud 


// include necessary libraries
#include <Wire.h>
#include <SPI.h>
#include <AudioCodec.h>

// create data variables for audio transfer
int left_in = 0x0000;
int left_out = 0x0000;
int right_in = 0x0000;
int right_out = 0x0000;


void setup() {
  AudioCodec_init(); // setup codec registers
  // call this last if setting up other parts
}

void loop() {
  while (1); // reduces clock jitter
}

// timer5 interrupt routine - all data processed here
ISR(TIMER5_COMPA_vect, ISR_NAKED) { // dont store any registers

  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
 
  // pass data through
  left_out = left_in;
  right_out = right_in;
 
  // dont forget to return from interrupt
  reti();
}




Code: Select all
// AudioCodec.h
// guest openmusiclabs 7.28.11
// this is the library file for ARDUINO -> there is a different
// file for Maple, make sure you are using the right one.
// place this file in the libraries file of your Arduino sketches folder
// e.g. C:\Documents and Settings\user\My Documents\Arduino\libraries\
// you may have to create the \libraries folder
//
// updated for arduino1.0 - i2c commands changed, and "Arduino.h" added 1.9.12


#ifndef AudioCodecMega_h // include guard
#define AudioCodecMega_h

//#include "WProgram.h"
#include "Arduino.h"
#include <avr/pgmspace.h>
#include "mult16x16.h"
#include "mult16x8.h"
#include "mult32x16.h"


#ifndef SAMPLE_RATE
  #define SAMPLE_RATE 44
#elif (SAMPLE_RATE == 88)||(SAMPLE_RATE == 44)||(SAMPLE_RATE == 22)||(SAMPLE_RATE == 8)||(SAMPLE_RATE == 2)
#else
  #error SAMPLE_RATE value not defined
#endif

#ifndef ADCHPD
  #define ADCHPD 0
#elif (ADCHPD == 0)||(ADCHPD == 1)
#else
  #error ADCHPD value not defined
#endif

#ifndef ADCS
  #define ADCS 2
#elif (ADCS >=0)&&(ADCS <= 2)
#else
  #error ADCS value not defined
#endif

#ifndef HYST
  #define HYST 32
#elif (HYST >= 0)&&(HYST <= 255)
#else
  #error HYST value not defined
#endif

#ifndef LINVOL
  #define LINVOL 23
#elif (LINVOL >= 0) && (LINVOL <= 0x1f)
#else
  #error LINVOL value not defined
#endif

#ifndef RINVOL
  #define RINVOL 23
#elif (RINVOL >= 0) && (RINVOL <= 0x1f)
#else
  #error RINVOL value not defined
#endif

#ifndef LHPVOL
  #define LHPVOL 121
#elif (LHPVOL == 0) || ((LHPVOL >= 0x30) && (LHPVOL <= 0x7f))
#else
  #error LHPVOL value not defined
#endif

#ifndef RHPVOL
  #define RHPVOL 121
#elif (RHPVOL == 0) || ((RHPVOL >= 0x30) && (RHPVOL <= 0x7f))
#else
  #error RHPVOL value not defined
#endif

#ifndef MICBOOST
  #define MICBOOST 0
#elif (MICBOOST == 0)||(MICBOOST == 1)
#else
  #error MICBOOST value not defined
#endif

#ifndef MUTEMIC
  #define MUTEMIC 1
#elif (MUTEMIC == 0)||(MUTEMIC == 1)
#else
  #error MUTEMIC value not defined
#endif

#ifndef INSEL
  #define INSEL 0
#elif (INSEL == 0)||(INSEL == 1)
#else
  #error INSEL value not defined
#endif

#ifndef BYPASS
  #define BYPASS 0
#elif (BYPASS == 0)||(BYPASS == 1)
#else
  #error BYPASS value not defined
#endif

#ifndef DACSEL
  #define DACSEL 1
#elif (DACSEL == 0)||(DACSEL == 1)
#else
  #error DACSEL value not defined
#endif

#ifndef SIDETONE
  #define SIDETONE 0
#elif (SIDETONE == 0)||(SIDETONE == 1)
#else
  #error SIDETONE value not defined
#endif

#ifndef SIDEATT
  #define SIDEATT 0
#elif (SIDEATT >= 0)&&(SIDEATT <= 3)
#else
  #error SIDEATT value not defined
#endif


// setup variables for ADC
#if ADCS == 0
  // do nothing
#elif ADCS == 1
  unsigned char _i = 64;
  unsigned int _mod0temp = 0x0000;
#elif ADCS == 2
  unsigned char _i = 130;
  unsigned int _mod0temp = 0x0000;
  unsigned int _mod1temp = 0x0000;
#endif


static inline void AudioCodec_init(void) {

  // setup spi peripheral
  pinMode (53, OUTPUT);
  digitalWrite(53, LOW); // set ss pin to output low
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE0);
 
  // setup i2c pins and configure codec
  // the new Wire library has trouble with 0x00, so (uint8_t) is added
  Wire.begin();
  Wire.beginTransmission(0x1a);
  Wire.write(0x0c); // power reduction register
  Wire.write((uint8_t)0x00); // turn everything on
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x0e); // digital data format
  Wire.write(0x03); // 16b SPI mode
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write((uint8_t)0x00); // left in setup register
  Wire.write((uint8_t)LINVOL);
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x02); // right in setup register
  Wire.write((uint8_t)RINVOL);
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x04); // left headphone out register
  Wire.write((uint8_t)LHPVOL);
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x06); // right headphone out register
  Wire.write((uint8_t)RHPVOL);
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x0a); // digital audio path configuration
  Wire.write((uint8_t)ADCHPD);
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x08); // analog audio pathway configuration
  Wire.write((uint8_t)((SIDEATT << 6)|(SIDETONE << 5)|(DACSEL << 4)|(BYPASS << 3)|(INSEL << 2)|(MUTEMIC << 1)|(MICBOOST << 0)));
  Wire.endTransmission();
 
  Wire.beginTransmission(0x1a);
  Wire.write(0x10); // clock configuration
  #if SAMPLE_RATE == 88
    Wire.write(0xbc);
  #elif SAMPLE_RATE == 44
    Wire.write(0xa0);
  #elif SAMPLE_RATE == 22
    Wire.write(0xe0);
  #elif SAMPLE_RATE == 8
    Wire.write(0xac);
  #elif SAMPLE_RATE == 2
    Wire.write(0xce);
  #endif
  Wire.endTransmission();

  Wire.beginTransmission(0x1a);
  Wire.write(0x12); // codec enable
  Wire.write(0x01);
  Wire.endTransmission();
 
  // setup ADCs
  #if ADCS == 0
    DIDR0 = (1 << ADC1D)|(1 << ADC0D); // turn off digital inputs for ADC0 and ADC1
  #elif (ADCS == 1) || (ADCS == 2)
    ADMUX = 0x40; // start with ADC0 - internal VCC for Vref
    ADCSRA = 0xe7; // ADC enable, autotrigger, ck/128
    ADCSRB = 0x00; // free running mode
    DIDR0 = (1 << ADC1D)|(1 << ADC0D); // turn off digital inputs for ADC0 and ADC1
  #endif
 
  // setup timer5 for codec clock division
  TCCR5A = 0x00; // set to CTC mode
  TCCR5B = 0x0f; // set to CTC mode, external clock
  TCCR5C = 0x00; // not used
  TCNT5H = 0x00; // clear the counter
  TCNT5H = 0x00;
  #if SAMPLE_RATE == 88
    OCR5AH = 0x00; // set the counter top
    OCR5AL = 0x3f;
  #elif (SAMPLE_RATE == 44) || (SAMPLE_RATE == 22)
    OCR5AH = 0x00; // set the counter top
    OCR5AL = 0x7f;
  #elif SAMPLE_RATE == 8
    OCR5AH = 0x02; // set the counter top
    OCR5AL = 0xbf;
  #elif SAMPLE_RATE == 2
    OCR5AH = 0x04; // set the counter top
    OCR5AL = 0x7f;
  #endif
  TIMSK5 = 0x02; // turn on compare match interrupt
 
  // turn off all enabled interrupts (delay and wire)
  TIMSK0 = 0x00;
  TWCR = 0x00;

  sei(); // turn on interrupts
}


// adc sample routine
// this creates relatively low noise 16b values from adc samples
#if ADCS == 0
  static inline void AudioCodec_ADC() {
    // do nothing
  }
#elif ADCS == 1
  static inline void AudioCodec_ADC(unsigned int* _mod0value) {
    if (ADCSRA & (1 << ADIF)) { // check if sample ready
      _mod0temp += ADCL; // fetch ADCL first to freeze sample
      _mod0temp += (ADCH << 8); // add to temp register
      ADCSRA = 0xf7; // reset the interrupt flag
      if (--_i == 0) { // check if enough samples have been averaged
        // add in hysteresis to remove jitter
        if (((_mod0temp - *_mod0value) < HYST) || ((*_mod0value - _mod0temp) < HYST)) {
        }
        else {
          *_mod0value = _mod0temp; // move temp value
   }
        _mod0temp = 0x0000; // reset temp value
        _i = 64; // reset counter
      }
    }
  }
#elif ADCS == 2
  static inline void AudioCodec_ADC(unsigned int* _mod0value, unsigned int* _mod1value) {
    if (ADCSRA & (1 << ADIF)) { // check if sample ready
      --_i; // check which sample we are on
      if (_i == 129) { // do nothing, first sample after mux change
      }
      else if (_i >= 65) { // sample ADC0
        _mod0temp += ADCL; // fetch ADCL first to freeze sample
        _mod0temp += (ADCH << 8); // add to temp register
        if (_i == 65) { // check if enough samples have been averaged
          // add in hysteresis to remove jitter
          if (((_mod0temp - *_mod0value) < HYST) || ((*_mod0value - _mod0temp) < HYST)) {
          }
          else {
            *_mod0value = _mod0temp; // move temp value
       }
          _mod0temp = 0x0000; // reset temp value
          ADMUX = 0x41; // switch to ADC1
        }
      }
      else if (_i < 64) { // sample ADC1, first sample (64) after mux change ignored
        _mod1temp += ADCL; // fetch ADCL first to freeze sample
        _mod1temp += (ADCH << 8); // add to temp register
        if (_i == 0) { // check if enough samples have been averaged
          // add in hysteresis to remove jitter
          if (((_mod1temp - *_mod1value) < HYST) || ((*_mod1value - _mod1temp) < HYST)) {
          }
          else {
            *_mod1value = _mod1temp; // move temp value
       }
          _mod1temp = 0x0000; // reset temp value
          ADMUX = 0x40; // switch to ADC0
          _i = 130; // reset counter
        }
      }
      ADCSRA = 0xf7; // reset the interrupt flag
    }
  }
#endif


// codec data transfer function
static inline void AudioCodec_data(int* _lin, int* _rin, int _lout, int _rout) {

  int _out_temp = _lout;
  PORTB |= (1<<PORTB0);  // toggle ss pina
  asm volatile ("out %0, %B1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );
  PORTB &= ~(1<<PORTB0); // toggle ss pin
  while(!(SPSR & (1<<SPIF))){ // wait for data transfer to complete
  }
  asm volatile ("out %0, %A1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );
  asm volatile ("in r3, %0" : : "I" (_SFR_IO_ADDR(SPDR)) );
  _out_temp = _rout;
  while(!(SPSR & (1<<SPIF))){ // wait for data transfer to complete
  }
  asm volatile ("out %0, %B1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );
  asm volatile ("in r2, %0" : : "I" (_SFR_IO_ADDR(SPDR)) );
  asm volatile ("movw %0, r2" : "=r" (*_lin) : );
  while(!(SPSR & (1<<SPIF))){ // wait for data transfer to complete
  }
  asm volatile ("out %0, %A1" : : "I" (_SFR_IO_ADDR(SPDR)), "r" (_out_temp) );
  asm volatile ("in r3, %0" : : "I" (_SFR_IO_ADDR(SPDR)) );
  while(!(SPSR & (1<<SPIF))){ // wait for data transfer to complete
  }
  asm volatile ("in r2, %0" : : "I" (_SFR_IO_ADDR(SPDR)) );
  asm volatile ("movw %0, r2" : "=r" (*_rin) : );
}


#endif // end include guard


scott2
 
Posts: 15
Joined: Thu Sep 27, 2012 5:48 pm

Re: Using with Arduino Mega 2560

Postby guest » Mon Nov 05, 2012 4:33 am

i will see if i can get my hands on a mega, and give it a go as well. in the meantime, you can put some code in there that turns on and off an led, just to see if its going into the main loop, or going into the interrupt. that will help see where it is getting hung up.
guest
Site Admin
 
Posts: 449
Joined: Thu May 20, 2010 11:58 pm

Re: Using with Arduino Mega 2560

Postby scott2 » Mon Nov 05, 2012 2:22 pm

guest wrote:i will see if i can get my hands on a mega, and give it a go as well. in the meantime, you can put some code in there that turns on and off an led, just to see if its going into the main loop, or going into the interrupt. that will help see where it is getting hung up.


Oh, good call re~using LEDs to debug that. I'll play around with that today. If you'd like, I can lend you my Mega / mail it off tomorrow, as I'm not really using it. I was just hoping to figure out what exactly the issue is with getting the codec-shield working on it, as that might lend some sort of important insight as I get ready to port the drivers to the PIC-based Max32.

Speaking of getting ready to port stuff, I pored over (in great detail) your driver code for the Uno/Maple, their respective datasheets, the CODEC chip datasheet, and some tutorials on GCC's ASM call. I learned a TON from that experience, so major props on your work on this project.
scott2
 
Posts: 15
Joined: Thu Sep 27, 2012 5:48 pm

Re: Using with Arduino Mega 2560

Postby guest » Mon Nov 05, 2012 7:14 pm

i should be able to borrow a mega from someone nearby.

glad to hear youre having some fun, and its not all painful debugging.
guest
Site Admin
 
Posts: 449
Joined: Thu May 20, 2010 11:58 pm

Previous

Return to Audio Codec Shield

Who is online

Users browsing this forum: No registered users and 1 guest


cron