¿Reproducir archivos de audio WAV desde una tarjeta SD en la placa de cableado?

Estoy usando el marco de cableado para construir un despertador personalizado. Hasta ahora, he podido trabajar con varias bibliotecas de Arduino en Wiring, simplemente al incluir Wiring.h en lugar de Arduino.h, como sugirió el creador de Wiring.

En cuanto al audio, he usado la biblioteca TMRpcm en Arduino Uno con éxito. Uno necesita tener una SD o una micro SD configurada, convertir los archivos de audio a un formato específico (WAV, 8-bits, 16kHz), opcionalmente hacer un circuito amplificador, y similares. eso ya lo tengo hecho Todo funciona en el mencionado Arduino.

Sin embargo, dado que Wiring S me da el doble de memoria que Arduino Uno (mi script ya supera la memoria de Arduino UNO), me gustaría implementar mi proyecto en Wiring. Estoy trabajando con Wiring S , Wiring v.1.0.1-dev como IDE, y ya he cambiado todo include <Arduino.h>en include <Wiring.h>todos los archivos de la biblioteca TMRpcm.

Cuando ejecuto el ejemplo básico (ajustando el nombre del archivo de audio y configurando SD_ChipSelectPin en 20 y el pin del altavoz en 16), aparece el siguiente mensaje de error:

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

Si comento estas definiciones en la biblioteca (archivo TMRpcm.cpp) o en el archivo WHardwareTimer.cpp incluido en Wiring, el código sí compila y puedo subirlo a mi Wiring S, pero el archivo de audio no se reproduce o no se puede escuchó.

Aquí puede obtener un archivo de audio de muestra de 31 KB (ya convertido al formato requerido).

¿Podría por favor ayudarme a resolver este problema? ¿Qué me estoy perdiendo? Puedo proporcionarle más detalles si es necesario.

Los errores se deben a que las interrupciones del temporizador utilizadas en la biblioteca también se utilizan en las bibliotecas principales de Wiring, por lo que existe un conflicto y, por lo tanto, no se compilará (__vector_n es una rutina ISR). Puede ser más simple simplemente agregar una entrada en el archivo boards.txt en el IDE de Arduino. El núcleo de Arduino es compatible con los dispositivos 644P (muchos usan el 1284P, que es solo el primo más grande del 644). Luego, puede compilar utilizando Arduino IDE y core libs y cargarlo en su placa Wiring S. De esa manera, no necesita portar las bibliotecas a las bibliotecas centrales de cableado.
Solo como referencia, __vector_15es ISR(TIMER1_OVF_vect)y __vector_12esISR(TIMER1_CAPT_vect)
Gracias por el comentario. La biblioteca TMRpcm tiene alguna opción para usar otro temporizador (TIMER2), probaré esa opción y si no funciona, tomaré su sugerencia de compilar usando Arduino IDE.
No hubo suerte con TIMER2, interfiere con otro temporizador definido por Wiring. Además, agregar una nueva placa a boards.txt era "fácil" antes de Arduino 1.5, luego cambiaron la especificación y ahora es complejo para usuarios como yo. No he logrado agregar Wiring S a Arduino 1.6.2. Lo agregué a Arduino 1.0.6, pero el script arroja muchos errores para tipos comunes como Byte y String. Todavía atascado.
En la versión 1.0.6, ¿te acordaste de volver a poner tus cambios en #include "Arduino.h"?
No tengo Arduino 1.6.x descargado, pero basándome en mirar el archivo boards.txt en Arduino github Repo, esta nueva entrada debería funcionar para Wiring S (no probado, avísame si no es así): astroeq .co.uk/FileDump/wiringS.txt
Sí, estoy usando las bibliotecas originales de Arduino 1.0.6 (es decir, con Arduino.h). Lanza errores desagradables, parece que muchas cosas han cambiado desde entonces. Por otro lado, probaré el archivo .txt que mencionaste y te lo haré saber.
¡Hay esperanza! El Wiring S aparece ahora en Boards, sin embargo, manipulé tanto la carpeta Arduino-1.6.2/hardware/Wiring/ que no estoy seguro de si funcionará. Yo lo haré saber.
Definitivamente no parece ser tan fácil. Recibo errores al compilar porque me faltan " recetas " para compilar el script. También se requiere una estructura de carpetas, pero logré imitarla como hardware/Wiring/avr/ What's inside platform.txt está más allá de mi comprensión.
No debería necesitar una carpeta de hardware/cableado, solo coloque esa entrada en el archivo boards.txt para el núcleo de Arduino. El 644p es compatible (no oficialmente) con el núcleo estándar de Arduino.
Probablemente tenga 16kHz como tasa de bits, no MHz.
@TomCarpenter Gracias por su ayuda, tiene razón, ahora puedo seleccionar Wiring S de Arduino IDE. El código se compila y puedo cargarlo en mi Wiring S. Sin embargo, no se escucha el sonido. Todavía creo que es por los alfileres. No estoy seguro si los enderecé (CS:20 y 16). Puede deberse a otra cosa, claro.
@tehwalris Tienes razón, he editado la pregunta. ¡Gracias!
Ah, por supuesto, esta línea deberá cambiarse en el archivo boards.txt: wiring_s.build.variant=standardpara que sea algo así wiring_s.build.variant=wirings, deberá agregar una carpeta 'wirings' en la carpeta de variantes del núcleo de Arduino, agregando un archivo pins_arduino.h adecuado para coincidir con el 644p. Este archivo es para el 1284, que es prácticamente el mismo, por lo que debería ser un buen punto de partida: astroeq.co.uk/FileDump/pins_arduino.h Puede usarlo directamente y simplemente averiguar qué número de pin digital corresponde con el cableado Tablero S, o actualice la numeración para que coincida.
@TomCarpenter Gracias por los consejos, parece el camino a seguir. Sin embargo, resulta que Wiring S tiene una configuración de PIN diferente a AtMega644p (ver wiki.wiring.co/images/e/e7/M644_wiring_pin_map.png ) Puedo configurar esos pines (en pins_arduino.h) para que coincidan con Wiring S, sin embargo, parece que también se necesitan algunas funciones. Ya que tratan con PROGMEM creo que requieren algo de cuidado. Vea lo que tengo en este momento (la negrita indica lo que ya ajusté): titanpad.com/wiringspins
Actualizado para ti.
Muchas gracias @TomCarpenter. Todo parece funcionar ahora (es decir, la pantalla LCD, el sensor de temperatura, el reloj en tiempo real, la configuración de la alarma), excepto por el sonido: realmente no sé cómo abordar esto, intentaré con diferentes pines para la salida de audio ( el SS/CS funciona bien). También echaré un vistazo al código de la biblioteca para ver si hay algo raro.
¡Eureka! Como te dije, los pines fueron un factor aquí. Siempre estaba intentando con los pines 16 o 4, pero fue el pin 6 el que funcionó (aunque no sé por qué) para la salida de audio. Ahora todas las funciones de alarma funcionan. Le pediré un último favor @TomCarpenter, por favor ponga cualquiera de sus comentarios o un resumen (con lo que se sienta cómodo) como respuesta, merece muchos puntos por su orientación. ¡Muchas gracias!
@TomCarpenter El sitio también le agradecería si publica una respuesta, para que pueda marcarla como aceptada y, por lo tanto, "cerrar" correctamente esta pregunta. :)
Hecho. Pido disculpas por la demora.
No te preocupes, pensé que habías decidido no publicar la respuesta, pero tuve que insistir. :D

Respuestas (1)

Para completar, puede determinar que los errores están relacionados con las interrupciones por el hecho de que los nombres de las funciones a las que se hace referencia en el error son __vector_(n), estos se refieren a vectores de interrupción específicos. Para averiguar exactamente cuáles, debe consultar la tabla de vectores en la hoja de datos de AVR. Solo para ser incómodo, en el código compilado los vectores están indexados en 0 pero en la hoja de datos están indexados en 1, así que para identificar el vector correcto, agregue 1 al (n)mensaje de error y búsquelo en la hoja de datos.

Para el ATMega644(P):

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

Por lo tanto, son vectores para el desbordamiento del temporizador 1 y la captura de entrada. Creo en el Arduino Core estándar, este no se usa, pero en el núcleo Wiring S ya debe ser usado por algo.

La buena noticia es que el ATMega1284(p) funcionará con el núcleo estándar de Arduino, aunque de manera extraoficial. Como el 644(p) es de la misma serie, solo que anterior, el núcleo de Arduino debería funcionar sin modificaciones con el 644. Las únicas dos cosas que se requieren son:

  1. Una entrada de Boards.txt
  2. Un archivo pins_arduino.h

Al crear estas entradas, debería poder compilar el código para la placa WiringS utilizando el IDE y el núcleo estándar de Arduino (para los cuales se diseñó la biblioteca).

Para la entrada boards.txt, lo siguiente debería funcionar:

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

Para el archivo pins_arduino.h, cree una carpeta 'wirings' dentro de la carpeta 'variants' del núcleo Arduino, luego cree un archivo pins_arduino.h con los siguientes contenidos:

#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
Muchas gracias Tom por tu completa respuesta. ¡Funcionó! ¡Pude cargar el código en mi Wiring S usando el IDE de Arduino y finalmente pude escuchar el audio!