Electronic – arduino – Playing WAV audio files from an SD card on Wiring board

arduinoaudioidelibrarywiring

I'm using the Wiring framework for building a custom alarm clock. So far, I've been able to work with several Arduino libraries on Wiring, just by including Wiring.h instead of Arduino.h, as suggested by Wiring's creator.

Regarding audio, I've used the TMRpcm library on Arduino Uno with success. One needs to have an SD or a micro SD configured, convert the audio files to a specific format (WAV, 8-bits, 16kHz), optionally make an amplifier circuit, and the like. I already have that done. All works on the aforementioned Arduino.

However, since Wiring S gives me twice the memory than Arduino Uno (my script already exceeds Arduino UNO's memory), I'd like to implement my project on Wiring. I'm working with a Wiring S, Wiring v.1.0.1-dev as IDE, and already changed all include <Arduino.h> by include <Wiring.h> on all files in the TMRpcm library.

When I run the basic example (adjusting the audio file name and setting the SD_ChipSelectPin to 20, and the speaker pin to 16) I get the following error message:

core.a(WHardwareTimer.cpp.o): In function `__vector_15':
C:\Users\toshiba\Downloads\wiring-v1.0.1-dev\cores\AVR8Bit/WHardwareTimer.cpp:140: multiple definition of `__vector_15'
TMRpcm\TMRpcm.cpp.o:C:\Users\toshiba\Downloads\wiring-v1.0.1-dev\libraries\TMRpcm/TMRpcm.cpp:650: first defined here
core.a(WHardwareTimer.cpp.o): In function `__vector_12':
C:\Users\toshiba\Downloads\wiring-v1.0.1-dev\cores\AVR8Bit/WHardwareTimer.cpp:145: multiple definition of `__vector_12'
TMRpcm\TMRpcm.cpp.o:C:\Users\toshiba\Downloads\wiring-v1.0.1-dev\libraries\TMRpcm/TMRpcm.cpp:569: first defined here
collect2.exe: error: ld returned 1 exit status

If I comment these definitions in the library (TMRpcm.cpp file) or in the WHardwareTimer.cpp file included in Wiring, the code does compile and I can upload it to my Wiring S, but the audio file is not reproduced or it cannot be heard.

Here you can get a 31KB sample audio file (already converted to the required format).

Could you please help me solve this problem? What am I missing? I can provide you with more details if needed.

Best Answer

For completeness, you can work out that the errors are related to interrupts by the fact that the function names being referenced in the error are __vector_(n), these refer to specific interrupt vectors. To find out exactly which ones you have to refer to the vector table in the AVR datasheet. Just to be awkward, in the compiled code the vectors are 0 indexed but in the datasheet they are 1 indexed, so to identify the correct vector, add 1 to the (n) in the error message and look it up in the datasheet.

For the ATMega644(P):

__vector_15 is ISR(TIMER1_OVF_vect)
__vector_12 is ISR(TIMER1_CAPT_vect)

So they are vectors for Timer 1 Overflow and Input Capture. I believe in the standard Arduino Core, this is unused, but in the Wiring S core it must already be used by something.

The good news is that the ATMega1284(p) will work with the standard Arduino core, though unofficially. As the 644(p) is from the same series, just an earlier one, the Arduino core should work without modification with the 644. The only two things that are required are:

  1. A Boards.txt entry
  2. A pins_arduino.h file

By creating these entries, you should be able to compile code for the WiringS board using the standard Arduino IDE and core (for which the library was designed).

For the boards.txt entry, the following should work:

wiring_s.name=Wiring S @ 16 MHz
wiring_s.upload.tool=avrdude 
wiring_s.upload.protocol=wiring 
wiring_s.upload.maximum_size=63488 
wiring_s.upload.maximum_data_size=4096
wiring_s.upload.speed=115200 

wiring_s.bootloader.tool=avrdude 
wiring_s.bootloader.low_fuses=0xF7 
wiring_s.bootloader.high_fuses=0xD4 
wiring_s.bootloader.extended_fuses=0xFD 
wiring_s.bootloader.unlock_bits=0x3F
wiring_s.bootloader.lock_bits=0x2F 
wiring_s.bootloader.file=Wiring/WiringBoot_WiringS.hex 

wiring_s.build.mcu=atmega644p 
wiring_s.build.f_cpu=16000000L 
wiring_s.build.board=AVR_WIRINGS 
wiring_s.build.core=arduino 
wiring_s.build.variant=wirings

For the pins_arduino.h file, create a 'wirings' folder inside the 'variants' folder of the Arduino core, then create a pins_arduino.h file with the following contents:

#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <avr/pgmspace.h>

// ATMEL ATMEGA644/644P
//
//                       +---\/---+
//          (D 16) PB0 1 |        | 40 PA0 (D 24) AI 0
//          (D 17) PB1 2 |        | 39 PA1 (D 25) AI 1
//     INT2 (D 18) PB2 3 |        | 38 PA2 (D 26) AI 2
//      PWM (D 19) PB3 4 |        | 37 PA3 (D 27) AI 3
//   PWM/SS (D 20) PB4 5 |        | 36 PA4 (D 28) AI 4
//     MOSI (D 21) PB5 6 |        | 35 PA5 (D 29) AI 5
// PWM/MISO (D 22) PB6 7 |        | 34 PA6 (D 30) AI 6
//  PWM/SCK (D 23) PB7 8 |        | 33 PA7 (D 31) AI 7
//                 RST 9 |        | 32 AREF
//                VCC 10 |        | 31 GND 
//                GND 11 |        | 30 AVCC
//              XTAL2 12 |        | 29 PC7 (D 15) 
//              XTAL1 13 |        | 28 PC6 (D 14) 
//      RX0 (D 0) PD0 14 |        | 27 PC5 (D 13) TDI
//      TX0 (D 1) PD1 15 |        | 26 PC4 (D 12) TDO
// INT0 RX1 (D 2) PD2 16 |        | 25 PC3 (D 11) TMS
// INT1 TX1 (D 3) PD3 17 |        | 24 PC2 (D 10) TCK
//      PWM (D 4) PD4 18 |        | 23 PC1 (D  9) SDA
//      PWM (D 5) PD5 19 |        | 22 PC0 (D  8) SCL
//      PWM (D 6) PD6 20 |        | 21 PD7 (D  7) PWM
//                       +--------+
//


#define NUM_DIGITAL_PINS            32
#define NUM_ANALOG_INPUTS           8
#define analogInputToDigitalPin(p)  ((p < 8) ? (p) + 24 : -1)

#define digitalPinHasPWM(p)         ((p) == 4 || (p) == 5 || (p) == 6 || (p) == 7 || (p) == 19 || (p) == 20 || (p) == 22 || (p) == 23)

#define digitalPinToAnalogPin(p)    ( (p) >= 24 && (p) <= 31 ? (p) - 24 : -1 )
#define analogPinToChannel(p)        ( (p) < NUM_ANALOG_INPUTS ? (p) : -1)

static const uint8_t SS   = 20;
static const uint8_t MOSI = 21;
static const uint8_t MISO = 22;
static const uint8_t SCK  = 23;

static const uint8_t SDA = 9;
static const uint8_t SCL = 8;
static const uint8_t LED = 15;

static const uint8_t A0 = 24;
static const uint8_t A1 = 25;
static const uint8_t A2 = 26;
static const uint8_t A3 = 27;
static const uint8_t A4 = 28;
static const uint8_t A5 = 29;
static const uint8_t A6 = 30;
static const uint8_t A7 = 31;

#ifdef ARDUINO_MAIN

// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint16_t PROGMEM port_to_mode_PGM[] =
{
    NOT_A_PORT,
    (uint16_t) &DDRA,
    (uint16_t) &DDRB,
    (uint16_t) &DDRC,
    (uint16_t) &DDRD,
};

const uint16_t PROGMEM port_to_output_PGM[] =
{
    NOT_A_PORT,
    (uint16_t) &PORTA,
    (uint16_t) &PORTB,
    (uint16_t) &PORTC,
    (uint16_t) &PORTD,
};

const uint16_t PROGMEM port_to_input_PGM[] =
{
    NOT_A_PORT,
    (uint16_t) &PINA,
    (uint16_t) &PINB,
    (uint16_t) &PINC,
    (uint16_t) &PIND,
};

const uint8_t PROGMEM digital_pin_to_port_PGM[NUM_DIGITAL_PINS] =
{
  PD, // D0
  PD, // D1
  PD, // D2
  PD, // D3
  PD, // D4
  PD, // D5
  PD, // D6
  PD, // D7
  PC, // D8
  PC, // D9
  PC, // D10
  PC, // D11
  PC, // D12
  PC, // D13
  PC, // D14
  PC, // D15
  PB, // D16
  PB, // D17
  PB, // D18
  PB, // D19
  PB, // D20
  PB, // D21
  PB, // D22
  PB, // D23
  PA, // D24
  PA, // D25
  PA, // D26
  PA, // D27
  PA, // D28
  PA, // D29
  PA, // D30
  PA, // D31
};

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[NUM_DIGITAL_PINS] =
{
  _BV(0), // D0 PD0
  _BV(1), // D1 PD1
  _BV(2), // D2 PD2
  _BV(3), // D3 PD3
  _BV(4), // D4 PD4
  _BV(5), // D5 PD5
  _BV(6), // D6 PD6
  _BV(7), // D7 PD7
  _BV(0), // D8 PC0
  _BV(1), // D9 PC1
  _BV(2), // D10 PC2
  _BV(3), // D11 PC3
  _BV(4), // D12 PC4
  _BV(5), // D13 PC5
  _BV(6), // D14 PC6
  _BV(7), // D15 PC7
  _BV(0), // D16 PB0
  _BV(1), // D17 PB1
  _BV(2), // D18 PB2
  _BV(3), // D19 PB3
  _BV(4), // D20 PB4
  _BV(5), // D21 PB5
  _BV(6), // D22 PB6
  _BV(7), // D23 PB7
  _BV(0), // D24 PA0
  _BV(1), // D25 PA1
  _BV(2), // D26 PA2
  _BV(3), // D27 PA3
  _BV(4), // D28 PA4
  _BV(5), // D29 PA5
  _BV(6), // D30 PA6
  _BV(7), // D31 PA7
};

const uint8_t PROGMEM digital_pin_to_timer_PGM[NUM_DIGITAL_PINS] =
{
  NOT_ON_TIMER, // D0 PD0
  NOT_ON_TIMER, // D1 PD1
  NOT_ON_TIMER, // D2 PD2
  NOT_ON_TIMER, // D3 PD3
  TIMER1B,      // D4 PD4
  TIMER1A,      // D5 PD5
  TIMER2B,      // D6 PD6
  TIMER2A,      // D7 PD7
  NOT_ON_TIMER, // D8 PC0
  NOT_ON_TIMER, // D9 PC1
  NOT_ON_TIMER, // D10 PC2
  NOT_ON_TIMER, // D11 PC3
  NOT_ON_TIMER, // D12 PC4
  NOT_ON_TIMER, // D13 PC5
  NOT_ON_TIMER, // D14 PC6
  NOT_ON_TIMER, // D15 PC7
  NOT_ON_TIMER, // D16 PB0
  NOT_ON_TIMER, // D17 PB1
  NOT_ON_TIMER, // D18 PB2
  TIMER0A,      // D19 PB3
  TIMER0B,      // D20 PB4
  NOT_ON_TIMER, // D21 PB5
  NOT_ON_TIMER, // D22 PB6
  NOT_ON_TIMER, // D23 PB7
  NOT_ON_TIMER, // D24 PA0
  NOT_ON_TIMER, // D25 PA1
  NOT_ON_TIMER, // D26 PA2
  NOT_ON_TIMER, // D27 PA3
  NOT_ON_TIMER, // D28 PA4
  NOT_ON_TIMER, // D29 PA5
  NOT_ON_TIMER, // D30 PA6
  NOT_ON_TIMER, // D31 PA7
};

#endif // ARDUINO_MAIN
#endif // Pins_Arduino_h