DFPlayer Mini with ATTiny85, "volume" function not working

Hi all, I'm new to this forum and new to Arduino as I recently picked up a tutorial kit to learn the basics. After that I jumped into the deep end, as my goal is to implement Arduino for light and sound on a starship project I'm working on.

The issue:
I'm using a DFPlayer Mini in combination with an Arduino Uno. This works fine. But when I transfer the code to an ATTiny85 the code doesn't behave the same:

Almost everything works, except the player.volume() . For some reason the ATTiny85 doesn't seem to understand or process this variable, whatever number from 0 to 30 I set there, the volume of the sound always remains at max level.

Bootloader core that supports serial communication used for ATTiny85 is this one, by Sleemanj:

I tried searching for this combination or similar problem on the internet but am at a loss. Especially since all other commands works perfectly.

Code (with pin designations for ATTiny85). Please note, besides the DFPlayerMini_Fast library I also tried using the DFRobotDFPlayerMini library. But both give the same result.

#include "SoftwareSerial.h"
#include "DFPlayerMini_Fast.h"

long prev = 0;
int buttonState = 0;  // 0 = not pressed   --- 1 = long pressed --- 2 short pressed
int buttonPin = 2;    // The button used to trigger music and audio clips
int duration = 600;   // How long it takes to reach long press
int clipNumber = 0;   // counter for short audio clips
int trackNumber = 0;  // counter for music

// Use pins to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = 0;  // This MUST be pin 0 on ATtiny85 for serial to work! Connects to module's RX
static const uint8_t PIN_MP3_RX = 1;  // This MUST be pin 1 on ATtiny85 for serial to work! Connects to module's TX.
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFPlayerMini_Fast player;

void setup() {
  pinMode(buttonPin, INPUT);

  // Init USB serial port for debugging
  Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  softwareSerial.begin(9600);

  // Start communication with DFPlayer Mini
  if (player.begin(softwareSerial)) {
    Serial.println("OK");

    // Set volume to maximum (0 to 30).
    player.volume(20);

  } else {
    Serial.println("Connecting to DFPlayer Mini failed!");
  }
}

void loop() {

  buttonState = 0;
  if (digitalRead(buttonPin)) {
    prev = millis();
    buttonState = 1;
    while ((millis() - prev) <= duration) {
      if (!(digitalRead(buttonPin))) {
        buttonState = 2;
        break;
      }
    }
  }

  if (!buttonState) {  // TODO nothing is pressed
  }

  else if (buttonState == 1) {          // TODO button is pressed long
    clipNumber = (clipNumber + 1) % 5;  // modulo operator to track button presses

    if (clipNumber == 1) {
      player.playFromMP3Folder(11);  // Plays clip 11
      delay(3000);
    } else if (clipNumber == 2) {
      player.playFromMP3Folder(12);  // Plays clip 12
      delay(3000);
    } else if (clipNumber == 3) {
      player.playFromMP3Folder(13);  // Plays clip 13
      delay(3000);
    } else if (clipNumber == 4) {
      player.playFromMP3Folder(14);  // Plays clip 14
      delay(3000);
    } else {
      player.playFromMP3Folder(15);  // Plays clip 15
      delay(3000);
    }
  } else {
  }

  if (buttonState == 2) {                 //TODO button is pressed short
    delay(300);                           // Delay for a period of time (in milliseconds). Useful for debounce
    trackNumber = (trackNumber + 1) % 4;  // modulo operator to track button presses

    if (trackNumber == 1) {
      player.playFromMP3Folder(1);  // Plays track 1
    } else if (trackNumber == 2) {
      player.stop();  // Stop playing
    } else if (trackNumber == 3) {
      player.playFromMP3Folder(2);  // Plays track 2
    } else {
      player.stop();  // Stop playing
    }
  } else {
  }
}

And the pin layout of the ATTiny85 in the Sleemanj core:

Do you have a USB-to-serial adapter?

If so, you could connect it to the DFPlayer TX pin and GND, then monitor the output in a serial terminal to check whether the hexadecimal frame and checksum sent by the ATtiny85 are correct.

This would help determine if the issue is not caused by a timing glitch or similar SoftwareSerial problem.

According to pinout, you connect your Serial and SoftwareSerial to same pins 0 & 1. You can't expect to use both serials at the time without issues.

When you print the debug messages to the Serial, it sends also to DFPlayer and can interrupt it's work. Comment outputting "OK" message in this peace of the code :

and check whether the volume will change.

Thank you both for helping!

I don't have a serial to USB cable, but I tried commenting out the debug message before the volume command. Unfortunately this didn't do anything.

It did however push me to try something else: Use the example code from the DFPlayerMini_Fast github.

So that example code did work with the ATTiny85, including the volume. I'm not really sure why it works, but the only obvious difference I noticed that in the example the definition of RX and TX was moved to the beginning of the code, right after including the SoftwareSerial library instead of defining them as static constants.
I also named my serial "mySerial" as per the example, instead of ""softwareSerial". I don't know if that matters for the ATTiny85, as I'm now just glad it works.

So, problem solved. Below is my cleaned up working code:

#include <DFPlayerMini_Fast.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(1, 0); // RX, TX

DFPlayerMini_Fast player;

long prev = 0;
int buttonState = 0;  // 0 = not pressed   --- 1 = long pressed --- 2 short pressed
int buttonPin = 2;    // The button used to trigger music and audio clips
int duration = 600;   // How long it takes to reach long press
int clipNumber = 0;   // counter for short audio clips
int trackNumber = 0;  // counter for music

void setup() {

  pinMode(buttonPin, INPUT);

  Serial.begin(9600);
  mySerial.begin(9600);
  player.begin(mySerial, true, false); // adding false statement to eliminate speaker pop at startup, why it works no idea
  delay(1000);
  player.volume(20); // Playback volume min 0 to max 30
  
}

void loop() {

  buttonState = 0;
  if (digitalRead(buttonPin)) {
    prev = millis();
    buttonState = 1;
    while ((millis() - prev) <= duration) {
      if (!(digitalRead(buttonPin))) {
        buttonState = 2;
        break;
      }
    }
  }

  if (!buttonState) {  // TODO nothing is pressed
  }

  else if (buttonState == 1) {          // TODO button is pressed long
    clipNumber = (clipNumber + 1) % 5;  // modulo operator to track button presses

    if (clipNumber == 1) {
      player.playFromMP3Folder(11);  // Plays clip 11
      delay(3000);
    } else if (clipNumber == 2) {
      player.playFromMP3Folder(12);  // Plays clip 12
      delay(3000);
    } else if (clipNumber == 3) {
      player.playFromMP3Folder(13);  // Plays clip 13
      delay(3000);
    } else if (clipNumber == 4) {
      player.playFromMP3Folder(14);  // Plays clip 14
      delay(3000);
    } else {
      player.playFromMP3Folder(15);  // Plays clip 15
      delay(3000);
    }
  } else {
  }

  if (buttonState == 2) {                 //TODO button is pressed short
    delay(300);                           // Delay for a period of time (in milliseconds). Useful for debounce
    trackNumber = (trackNumber + 1) % 4;  // modulo operator to track button presses

    if (trackNumber == 1) {
      player.playFromMP3Folder(1);  // Plays track 1
    } else if (trackNumber == 2) {
      player.stop();  // Stop playing
    } else if (trackNumber == 3) {
      player.playFromMP3Folder(2);  // Plays track 2
    } else {
      player.stop();  // Stop playing
    }
  } else {
  }
}

Compare. Your code:

Example code:

There are two obvious changes : i) you added a two parameters to player.begin() method and ii) a one second delay.

And I think that the addition the delay make the trick.

Ah yes, I didn't realize that difference. I had a previous version of the code with the true and false statements which works with the Arduino Uno. I left it out of my ATTiny85 code at some point probably because I was clutching at straws to get it to work.

It must be the added delay then. It worked on the Uno without the delay, but I'm guessing the ATTiny85 needs the delay because it processes the code slower?

Thanks again!

Add the delay to your previous code and we will see

I'm curious, but I'll have to try later. I cleared the breadboard as I'm currently integrating the DFPlayer as a second DFPlayer into my main project. Ideally I want to control my whole project with one IC (the Arduino Uno, and when all is finished just an ATMega328) but my main code got too bulky for me to comprehend. So I offloaded the second DFPlayer to the ATTiny85 as an experiment to make it more comprehensible to me.

Anyway, with Arduino code it looks like a nights' sleep really does wonders to clear the mind and it looks like I'm getting somewhere with the main project. :slight_smile:

I'll report back when I get around to testing with the ATTiny85 again!