Воспроизведение аудиофайлов WAV с SD-карты на монтажной плате?

Я использую платформу Wiring для создания собственного будильника. До сих пор мне удавалось работать с несколькими библиотеками Arduino в Wiring, просто включив Wiring.h вместо Arduino.h, как предложил создатель Wiring.

Что касается звука, я успешно использовал библиотеку TMRpcm на Arduino Uno. Нужно настроить SD или micro SD, преобразовать аудиофайлы в определенный формат (WAV, 8 бит, 16 кГц), при желании сделать схему усилителя и тому подобное. Я это уже сделал. Все работает на вышеупомянутой Arduino.

Однако, поскольку Wiring S дает мне в два раза больше памяти, чем Arduino Uno (мой скрипт уже превышает память Arduino UNO), я хотел бы реализовать свой проект на Wiring. Я работаю с Wiring S , Wiring v.1.0.1-dev как IDE и уже изменил все include <Arduino.h>файлы include <Wiring.h>в библиотеке TMRpcm.

Когда я запускаю базовый пример (настраивая имя аудиофайла и устанавливая для SD_ChipSelectPin значение 20, а для контакта динамика — 16), я получаю следующее сообщение об ошибке:

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

Если я прокомментирую эти определения в библиотеке (файл TMRpcm.cpp) или в файле WHardwareTimer.cpp, входящем в состав Wiring, код скомпилируется, и я смогу загрузить его на свой Wiring S, но аудиофайл не воспроизводится или его невозможно воспроизвести. слышал.

Здесь вы можете получить образец аудиофайла размером 31 КБ (уже преобразованный в нужный формат).

Не могли бы вы помочь мне решить эту проблему? Что мне не хватает? Я могу предоставить вам более подробную информацию, если это необходимо.

Ошибки связаны с тем, что прерывания таймера, используемые в библиотеке, также используются в основных библиотеках Wiring, поэтому возникает конфликт, и, следовательно, он не будет компилироваться (__vector_n - это процедура ISR). Возможно, будет проще просто добавить запись в файл boards.txt в Arduino IDE. Ядро Arduino поддерживает устройства 644P (многие используют 1284P, который является просто старшим родственником 644). Затем вы можете просто скомпилировать с помощью Arduino IDE и основных библиотек и загрузить на свою плату Wiring S. Таким образом, вам не нужно портировать библиотеки в основные библиотеки проводки.
Просто для справки, __vector_15есть ISR(TIMER1_OVF_vect)и __vector_12естьISR(TIMER1_CAPT_vect)
Спасибо за комментарий. В библиотеке TMRpcm есть возможность использовать другой таймер (TIMER2), я попробую этот вариант, и если он не сработает, я приму ваше предложение по компиляции с помощью Arduino IDE.
Не повезло с TIMER2, он мешает другому таймеру, определенному Wiring. Кроме того, добавление новой платы в boards.txt было «легким» до Arduino 1.5, затем они изменили спецификацию, и теперь это сложно для таких пользователей, как я. Мне не удалось добавить Wiring S в Arduino 1.6.2. Я добавил его в Arduino 1.0.6, но скрипт выдает много ошибок для распространенных типов, таких как Byte и String. Все еще застряли.
В версии 1.0.6 вы не забыли вернуть свои изменения в #include «Arduino.h»?
У меня нет загруженной версии Arduino 1.6.x, но, судя по файлу boards.txt в репозитории Arduino github, эта новая запись должна работать для Wiring S (непроверено, дайте мне знать, если это не так): astroeq .co.uk/FileDump/wiringS.txt
Да, я использую оригинальные библиотеки в Arduino 1.0.6 (т.е. с Arduino.h). Выдает неприятные ошибки, кажется, что с тех пор многое изменилось. С другой стороны, я проверю упомянутый вами файл .txt и дам вам знать.
Есть надежда! Wiring S теперь указан в платах, однако я так много манипулировал папкой Arduino-1.6.2/hardware/Wiring/, что не уверен, будет ли она работать. Я дам Вам знать.
Определенно, это не кажется таким уж легким. Я получаю ошибки при компиляции, потому что мне не хватает " рецептов " для компиляции скрипта. Также требуется структура папок, но мне удалось сымитировать ее как hardware/Wiring/avr/ Что находится внутри platform.txt, я не понимаю.
Вам не нужна папка hardware/Wiring, просто поместите эту запись в файл boards.txt для ядра Arduino. 644p поддерживается (неофициально) стандартным ядром Arduino.
Вероятно, у вас битрейт 16 кГц, а не МГц.
@TomCarpenter Спасибо за вашу помощь, вы правы, теперь я могу выбрать Wiring S из Arduino IDE. Код компилируется, и я могу загрузить его в свой Wiring S. Однако звука не слышно. Я все же думаю, что это из-за булавок. Не уверен, правильно ли я их настроил (CS:20 и 16). Это может быть связано с чем-то другим, конечно.
@tehwalris Вы правы, я отредактировал вопрос. Спасибо!
Ах, конечно, эту строку нужно будет изменить в файле boards.txt: wiring_s.build.variant=standardчтобы она была примерно такой wiring_s.build.variant=wirings, тогда вам нужно будет добавить папку «wirings» в папку вариантов ядра Arduino, добавив подходящий файл pins_arduino.h в соответствует 644p. Этот файл предназначен для 1284, который почти такой же, поэтому он должен стать хорошей отправной точкой: astroeq.co.uk/FileDump/pins_arduino.h . Вы можете либо использовать его напрямую, либо просто определить, какой цифровой номер контакта соответствует проводке. S или обновите нумерацию, чтобы она соответствовала.
@TomCarpenter Спасибо за подсказки, кажется, это правильно. Однако оказалось, что Wiring S имеет другую конфигурацию PIN-кода, чем AtMega644p (см. wiki.wiring.co/images/e/e7/M644_wiring_pin_map.png ). Я могу установить эти контакты (в pins_arduino.h), чтобы они соответствовали проводке. S, однако, кажется, что некоторые функции также необходимы. Поскольку они имеют дело с PROGMEM, я думаю, что они требуют некоторой осторожности. Пожалуйста, посмотрите, что у меня есть на данный момент (жирным шрифтом выделено то, что я уже настроил): titanpad.com/wiringspins
Обновлено для вас.
Большое спасибо @TomCarpenter. Кажется, теперь все работает (то есть ЖК-дисплей, датчик температуры, часы реального времени, настройки будильника), кроме звука: я действительно не знаю, как с этим справиться, я попробую с другими контактами для аудиовыхода ( SS/CS работает хорошо). Я также посмотрю код библиотеки, чтобы увидеть, есть ли что-то странное.
Эврика! Как я уже говорил вам, булавки были фактором здесь. Я всегда пытался использовать контакты 16 или 4, но именно контакт 6 работал (хотя, не знаю почему) для вывода звука. Теперь все функции будильника работают. Я попрошу вас об одной последней услуге @TomCarpenter, пожалуйста, оставьте любой из ваших комментариев или резюме (то, что вам удобно) в качестве ответа, вы заслуживаете много баллов за свое руководство. Большое спасибо!
@TomCarpenter Сайт также поблагодарит вас, если вы опубликуете ответ, чтобы я мог пометить его как принятый и, следовательно, должным образом «закрыть» этот вопрос. :)
Сделанный. Извините за задержку.
Не беспокойтесь, я думал, вы решили не публиковать ответ, но мне пришлось настоять. :D

Ответы (1)

Для полноты вы можете понять, что ошибки связаны с прерываниями по тому факту, что имена функций, на которые ссылаются в ошибке __vector_(n), относятся к определенным векторам прерываний. Чтобы узнать, какие именно, вы должны обратиться к векторной таблице в таблице данных AVR. Просто чтобы не запутаться, в скомпилированном коде векторы имеют индекс 0, но в таблице данных они имеют индекс 1, поэтому, чтобы определить правильный вектор, добавьте 1 к в (n)сообщении об ошибке и найдите его в таблице данных.

Для ATMega644(P):

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

Таким образом, они являются векторами для переполнения таймера 1 и захвата ввода. Я верю, что в стандартном ядре Arduino это не используется, но в ядре Wiring S оно уже должно быть чем-то использовано.

Хорошей новостью является то, что ATMega1284(p) будет работать со стандартным ядром Arduino, хотя и неофициально. Поскольку 644(p) относится к той же серии, но более ранней, ядро ​​Arduino должно работать без модификации с 644. Требуются только две вещи:

  1. Запись Boards.txt
  2. Файл pins_arduino.h

Создав эти записи, вы сможете скомпилировать код для платы WiringS, используя стандартную среду разработки Arduino IDE и ядро ​​(для которого была разработана библиотека).

Для записи boards.txt должно работать следующее:

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

Для файла pins_arduino.h создайте папку «wirings» внутри папки «variants» ядра Arduino, затем создайте файл pins_arduino.h со следующим содержимым:

#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
Большое спасибо, Том, за исчерпывающий ответ. Это сработало! Я смог загрузить код в свой Wiring S с помощью Arduino IDE и наконец-то услышал звук!