Generar audio con PWM no funciona?

Hola a todos. El título del hilo suena poco descriptivo, así que voy a explicar cuál es el asunto.

Estoy usando un Arduino Mega, porque necesito almacenar un audio de aprox. 4 segundos, estéreo, 8 bits por muestra y a 22 KHz.
No hablo de usar tarjeta SD ni nada, porque el programa trabaja mediante interrupciones por timer.

Anteriormente en otro hilo, había mencionado sobre las limitaciones de los punteros en AVR (no más de 64 KB); pero eso no es problema debido a que ya encontré la solución.
El problema es que, al parecer, el PWM no está funcionando en mi programa; o no está leyendo los bytes de la memoria flash.

Agrego el código del programa para que verifiquen si es mal uso de los registros, o error al leer los bytes:

#include "close0.h"
#include "close1.h"
#include "close2.h"
#include "far0.h"
#include "far1.h"
#include "far2.h"
#include "far3.h"
#include "far4.h"
// Archivos con las muestras de los audios (8-bit PCM). Son arrays de unsigned char

#include <TimerOne.h>
// He aquí la librería que estoy utilizando.


#define GET_FAR_ADDRESS(var)                          \
  ({                                                    \
    uint_farptr_t tmp;                                \
    \
    __asm__ __volatile__(                             \
        \
        "ldi    %A0, lo8(%1)"           "\n\t"    \
        "ldi    %B0, hi8(%1)"           "\n\t"    \
        "ldi    %C0, hh8(%1)"           "\n\t"    \
        "clr    %D0"                    "\n\t"    \
        :                                             \
        "=d" (tmp)                                \
        :                                             \
        "p"  (&(var))                             \
                        );                                                \
    tmp;                                              \
  })
// Gracias a esta función escrita en ensamblador, es como consigo los punteros que necesito.
// Devuelve un tipo de dato que creo que es similar a unsigned long
  
volatile unsigned int sampleCount = 0;
volatile byte pointerIdx = 0;
// Trabajo con interrupciones, por eso es que cada decisión la tengo que basar en variables globales

//boolean selector = HIGH;
//uint_farptr_t cp[3];
uint_farptr_t fp[5];
//const unsigned int cl[] = {close0_len, close1_len, close2_len};
const unsigned int fl[] = {far0_len, far1_len, far2_len, far3_len, far4_len};
// Es conveniente agrupar en arrays, la información respecto a los datos de audio (dirección de memoria en donde inicia, y su longitud)

void setup() {
  //pinMode(2, INPUT_PULLUP); // Cuando resuelva el problema, hago uso de esto
  // Serial.begin(9600); // Depuración que ya hice.
  pinMode(4, OUTPUT); // Left (OCR0B)
  pinMode(13, OUTPUT); // Right (OCR0A)
  /*cp[0] = GET_FAR_ADDRESS(close0);
  cp[1] = GET_FAR_ADDRESS(close1);
  cp[2] = GET_FAR_ADDRESS(close2);*/ // Cuando resuelva el problema, hago uso de esto
  
  fp[0] = GET_FAR_ADDRESS(far0);
  // Serial.println(fp[0]);
  fp[1] = GET_FAR_ADDRESS(far1);
  // Serial.println(fp[1]);
  fp[2] = GET_FAR_ADDRESS(far2);
  // Serial.println(fp[2]);
  fp[3] = GET_FAR_ADDRESS(far3);
  // Serial.println(fp[3]);
  fp[4] = GET_FAR_ADDRESS(far4);
  // Serial.println(fp[4]);
  // Efectivamente sí consigo los punteros. En uno de ellos me imprime una dirección fuera de los 64 KB, así que asumo que funciona.
  
  TCCR0B = TCCR0B & 0b11111000 | 0x01; // Timer0, prescaler 1. Correcto?
  
  analogWrite(4, 1); // Initialize PWM mode on that pin (timer)
  analogWrite(13, 1);
  // Es necesario hacer esto para que los pines entren en "modo PWM"?
  Timer1.initialize();
  cli();
  Timer1.attachInterrupt(writeSamples, 45); // attachInterrupt(ISR, 22050 Hz)
  sei();
}

void loop() {
  //selector = digitalRead(2); // Cuando resuelva el problema, hago uso de esto
}

void writeSamples() { // Interrupción por CTC

  OCR0B = pgm_read_byte_far(fp[pointerIdx] + sampleCount); // Índices pares para el canal izquierdo
  sampleCount++;
  OCR0A = pgm_read_byte_far(fp[pointerIdx] + sampleCount); // Índices impares para el canal derecho
  // Se supone que pgm_read_byte_far elimina la restricción de 64 KB
  sampleCount++;
  if (sampleCount == fl[pointerIdx]) { // Acabé con el array?
    sampleCount = 0;
    pointerIdx++; // Siguiente fragmento del audio
    if (pointerIdx == 5) // No hay más fragmentos?
      pointerIdx = 0; // Volver todo al principio para así crear un bucle infinito
  }
  /*
   * La fragmentación se debe a dos razones:
   * 
   * 1. En AVR no se permiten arrays de más de 32767 bytes de longitud.
   * 2. Los datos se escriben contiguamente, pero no en orden. Con leerlo todo seguido, se escucharían las partes pero en orden incorrecto.
   */
}

No es problema de hardware. Por si no lo han notado, una salida está en el pin 13; por lo tanto, debería haber algo de luz en el LED incorporado… pero nada. :frowning:

Cualquier ayuda se le agradece de antemano… :slight_smile:

Hola Lucario, solo un comentario. Como quieres que alguien vea tu programa si no incluyes tus librerías?

Argh pensé que era obvio.

Este: TimerOne

Los archivos “close” y “far” no sé si será necesario que los adjunte también. Básicamente son algo como:

// Bla bla generado con bin2h
#include <avr/pgmspace>

const unsigned int close0_len = 32766;

const unsigned char close0[32766] PROGMEM = {
  /* 32766 bytes en formato hexadecimal */
}