XRAD'S DFRobot DF2301QG VR solved issue lockup

I have been using some newer arduino and teensy MCU's with the DF2301QG. The issue is that even with correct voice training, the DF board will lock up after it's first power down (waketime expired) and voice restart. It seemed like UART or I2C buffer was overflowed, or data corruption. Because with restart, it would work again until first voice timeout. Two new DF boards, same issue. Online, many people have this same problem. Also, initial '!' begin was not recognized. So, after a few attempts at different solutions, I found that the DF board needs at least 6 seconds after MCU boot BEFORE uploading any set modes. If the set modes serial print to your monitor, you are good to go. I have a bit of I2C code here that works in case anyone else wants to use try it. Just port it to your board...you can use the built in 'hello robot' and commands 'Turn on the light' and 'Turn off the light' with a new unmodified board for testing . pre loaded key command words can be found at bottom of wiki: SKU_SEN0539-EN_Gravity_Voice_Recognition_Module_I2C_UART-DFRobot


#include "DFRobot_DF2301Q.h"

#define TESTLED 13
const int LED_RIGHT_EYE = 4;  //teensy pins
const int LED_LEFT_EYE = 3;

 
//I2C communication
#define DF2301Q_I2C_ADDR 0x64
//#define DFRobot_DF2301Q_I2C(Serial1, DF2301Q_I2C_ADDR) ;
DFRobot_DF2301Q_I2C asr;

uint8_t wakeTime = 0;

void setup() {
  Serial.begin(115200);

  pinMode(TESTLED, OUTPUT);    //Init LED pin to output mode
  digitalWrite(TESTLED, LOW);  //Set LED pin to low
  pinMode(LED_RIGHT_EYE, OUTPUT);
  pinMode(LED_LEFT_EYE, OUTPUT); 
  pinMode(LED_LEFT_EYE, OUTPUT);
  
  delay(6000);  //must wait for DF2301Q_I2C boot!!
  // Init the sensor
  /*
  while (!(asr.begin())) {
    Serial.println("Communication with device failed, please check connection");
    delay(3000);
  }
  */
  asr.begin();//EDIT..moved begin to after DF2301Q boot delay
  //Serial.println("DF2301Q_I2C Begin");//EDIT to below
  asr.setVolume(7);     //value(1~7)
  asr.setMuteMode(1);   //value 1: mute, 0: unmute
  asr.setWakeTime(20);  //Wake-up duration (0-255)
  wakeTime = asr.getWakeTime();
  Serial.print("wakeTime = ");
  Serial.println(wakeTime); 
  if (wakeTime > 0){// NOTE: defaults to 0 if communication fails
    Serial.println("DF2301Q_I2C Begin OK");
  }
  //asr.playByCMDID(1);   // Wake-up command
}

void loop() {

  uint8_t CMDID = asr.getCMDID();


  switch (CMDID) {

    case 1:  //the first command is to 'WAKE'
      digitalWrite(LED_RIGHT_EYE, HIGH);
      digitalWrite(TESTLED, HIGH);
      Serial.println("HEY WALL-E");
      break;

    case 5:  //the first custom command begins at '5'

      digitalWrite(LED_RIGHT_EYE, HIGH);
      digitalWrite(LED_LEFT_EYE, HIGH);
      digitalWrite(TESTLED, HIGH);
      Serial.println("received 'LED ON',command flag '5'");
      break;

    case 6:
      digitalWrite(LED_RIGHT_EYE, LOW);
      digitalWrite(LED_LEFT_EYE, LOW);
      digitalWrite(TESTLED, LOW);
      Serial.println("received 'LED OFF',command flag '6'");
      break;

    case 7:
      for (int x; x <= 6; x++) {
        digitalWrite(LED_RIGHT_EYE, HIGH);
        digitalWrite(TESTLED, HIGH);
        delay(150);
        digitalWrite(LED_RIGHT_EYE, LOW);
        digitalWrite(TESTLED, LOW);
        delay(150);
      }
      /*
      digitalWrite(SDA, 0);
      digitalWrite(SCL, 0);
      delay(5);
      digitalWrite(SDA, 1);
      digitalWrite(SCL, 1);
      Serial1.flush();
      */
      Serial.println("I2C/serial1 Reset Performed");
      break;

    case 103:                                                           //If the command is “Turn on the light”
      digitalWrite(LED_RIGHT_EYE, HIGH);                                //Turn on the LED
      digitalWrite(TESTLED, HIGH);
      Serial.println("received'Turn on the light',command flag'103'");  //Serial transmits "received"Turn on the light",command flag"103
      break;

    case 104:                                                            //If the command is “Turn off the light”
      digitalWrite(LED_RIGHT_EYE, LOW);                                  //Turn off the LED
      digitalWrite(TESTLED, LOW);
      Serial.println("received'Turn off the light',command flag'104'");  //The serial transmits "received"Turn off the light",command flag"104""
      break;

    default:  //when voice recog is not active
      if (CMDID != 0) {
        Serial.print("CMDID = ");  //Printing command ID
        Serial.println(CMDID); 
      }
  }
  delay(300);
}
1 Like

BTW...DFRobot voice module code is blocking. After a few runs through the loop, if you are doing anything more serious than turning on or off a relay, the module locks up. I have read through the DFRobot voice library looking for a way to modify it, and also tried many different non-blocking codes with fade LED and servo motions, but it still locks up while trying to read the DFRobot in either UART or I2C (works fine on it's own as shown in my first post code) . So, ONE simple working answer to this is the following. I use two MCUs. I read the DFRobot voice unit with UART. I transmit the trained switch case integer via I2C to the second MCU. This works without issue and of course, the voice module code never locks up. Here are my codes in case anyone wants to use them. I am using arduino Wire and x2 Teensy 4.0s...

This is the voice side with DF module, and it 'sends' via Wire..

#include "DFRobot_DF2301Q.h"
#include <Wire.h>

#define TESTLED 13
const int LED_RIGHT_EYE = 4;  //teensy pins
const int LED_LEFT_EYE = 3;

//voice sercom 'voice' variable
int v = 0;

//UART serial1
DFRobot_DF2301Q_UART asr(/*hardSerial =*/&Serial1);


void setup() {
  Serial.begin(115200);

  Serial1.begin(9600);//teensy serial1 0,1

  pinMode(TESTLED, OUTPUT);     //Init LED pin to output mode
  digitalWrite(TESTLED, HIGH);  //Set LED pin to low


  delay(6000);  //must wait for DF2301Q_I2C boot!!

  asr.begin();  //EDIT..moved begin to after DF2301Q boot delay

  asr.settingCMD(DF2301Q_UART_MSG_CMD_SET_MUTE, 0);        //1: mute, 0: unmute
  asr.settingCMD(DF2301Q_UART_MSG_CMD_SET_VOLUME, 3);      //Volume range(1-7)
  asr.settingCMD(DF2301Q_UART_MSG_CMD_SET_WAKE_TIME, 20);  //Wake-up duration(0-255)
  //asr.settingCMD(DF2301Q_UART_MSG_CMD_SET_ENTERWAKEUP, 0);//0 = wake state

  Wire.begin();  //send from this teensy to Wire.read(1);
  Wire.setClock(100000L);
  //Wire.setSDA(18);
  //Wire.setSCL(19);

  delay(40);

  digitalWrite(TESTLED, LOW);
}

void loop() {

  uint8_t CMDID = asr.getCMDID();


  switch (CMDID) {

    case 1:  //the first command is to 'WAKE'
      v = 1;
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      digitalWrite(TESTLED, HIGH);
      Serial.println("HEY WALL-E");
      Serial.print("v = ");  //Printing command ID
      Serial.println(v);
      break;

    case 5:  //the first custom command begins at '5'
      v = 5;
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      digitalWrite(TESTLED, HIGH);
      Serial.println("received 'LED ON',command flag '5'");
      break;

    case 6:
      v = 6;
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      digitalWrite(TESTLED, LOW);
      Serial.println("received 'LED OFF',command flag '6'");
      break;

    case 7:
      v = 7;
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      break;

    case 103:   //If the command is “Turn on the light”
      v = 103;  //Turn on the LED
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      digitalWrite(TESTLED, HIGH);
      Serial.println("received'Turn on the light',command flag'103'");  //Serial transmits "received"Turn on the light",command flag"103
      break;

    case 104:
      v = 104;
      Wire.beginTransmission(1);
      Wire.write(v);
      Wire.endTransmission();
      digitalWrite(TESTLED, LOW);
      Serial.println("received'Turn off the light',command flag'104'");  //The serial transmits "received"Turn off the light",command flag"104""
      break;

    default:  //when voice recog is not active
      if (CMDID != 0) {
        v = 0;
        Serial.print("CMDID = ");  //Printing command ID
        Serial.println(CMDID);
      }
  }
  delay(300);
}

this is the 'receive' side...which will run more code based on Wire reads...


#include <Wire.h>

#define TESTLED 13

//voice sercom 'voice' variable
int v = 0;//do nothing at '0'

void receiveEvent(int bytes) {
  v = Wire.read();
  Serial.print("INCOMING WIRE READ INT: ");
  Serial.println(v);
}

void setup() {
  Serial.begin(115200);


  pinMode(TESTLED, OUTPUT);     //Init LED pin to output mode
  digitalWrite(TESTLED, HIGH);  //Set LED pin to low


  delay(6000);  //must wait for DF2301Q_I2C boot!!

  Wire.begin(1);
  Wire.setClock(100000L);
  //Wire.setSDA(18);
  //Wire.setSCL(19);
  Wire.onReceive(receiveEvent);
  delay(40);

  digitalWrite(TESTLED, LOW);
}

void loop() {

  switch (v) {
    
    case 1:  //the first command is to 'WAKE'
      digitalWrite(TESTLED, HIGH);
      Serial.println("RECEIVE from I2C: HEY WALL-E");
      v = 0; 
      break;

    case 5:  //the first custom command begins at '5'
      digitalWrite(TESTLED, HIGH);
      //Serial.println("RECEIVE from I2C: 'LED ON',command flag '5'");
      v = 0;
      break;

    case 6:
      digitalWrite(TESTLED, LOW);
      // Serial.println("RECEIVE from I2C: 'LED OFF',command flag '6'");
      v = 0;
      break;

    case 7:
      v = 0;
      break;

    case 103:
      digitalWrite(TESTLED, HIGH);
      //Serial.println("received'Turn on the light',command flag'103'");
      v = 0;
      break;

    case 104:
      digitalWrite(TESTLED, LOW);
      //Serial.println("received'Turn off the light',command flag'104'");
      v = 0;
      break;
  }
}

this was really helpful. was shocked when i was using and the i2c stopped transmitting. lol