I'm trying to start a connection from my Arduino Mega ADK to my Android but I keep getting the error below whenever I try to acc.powerOn()
Error: OSCOKIRQ failed to assert
This is the firmware that I'm trying to run:
#include <Wire.h>
#include <Servo.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
int led = 13;
int EnableMotors = 22;
int Motor1FW = 24;
int Motor1RW = 26;
int Motor2FW = 28;
int Motor2RW = 30;
AndroidAccessory acc("FRBB",
"UgvBr",
"DemoKit Arduino Board",
"1.0",
"http://www.android.com",
"0000000012345678");
// the setup routine runs once when you press reset:
void setup() {
// Setting Serial at 115200 bps
Serial.begin(115200);
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
// Set up motor configs
pinMode(EnableMotors, OUTPUT);
pinMode(Motor1FW, OUTPUT);
pinMode(Motor1RW, OUTPUT);
pinMode(Motor2FW, OUTPUT);
pinMode(Motor2RW, OUTPUT);
// Powering the accessory
acc.powerOn(); ///// <<<<<<<<<<< ERROR
}
// the loop routine runs over and over again forever:
void loop() {
if(acc.isConnected()){
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
digitalWrite(EnableMotors, HIGH);
digitalWrite(Motor1FW, HIGH);
digitalWrite(Motor2FW, HIGH);
delay(2000);
digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level)
digitalWrite(EnableMotors, LOW);
digitalWrite(Motor1FW, LOW);
digitalWrite(Motor2FW, LOW);
delay(2000);
}
}
I've been looking everywhere and I couldn't find a solution to this problem yet. I also tried the DemoKit with Arduino.app on 1.0.1, but still the same issue. I'm developing it using Mac, but I don't think that it is a problem.
For testing purposes, I uploaded a code to blink the LED, and it worked just fine.
Spent a good 8 hours having the exact same problem. Seems like the Max3421e.cpp is faulty. Try replacing:
boolean MAX3421E::reset()
{
byte tmp = 0;
regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
regWr( rUSBCTL, 0x00 ); //Remove the reset
while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable
tmp++; //timeout after 256 attempts
if( tmp == 0 ) {
return( false );
}
}
return( true );
}
with
boolean MAX3421E::reset()
{
regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
regWr( rUSBCTL, 0x00 ); //Remove the reset
while(!(regRd(rUSBIRQ) & bmOSCOKIRQ)) ;
}
In Max3421e.cpp located in the USB_Host_Shield library (in your Arduino IDE library folder).
Basically the change does not allow an exit until the PLL is really stabilized.
Worked for me at least, good luck
(Original hints and more about the fix here: http://arduino.cc/forum/index.php?topic=68205.0)
Use USB_Host_Shield_2.0 library with Arduino Mega ADK.
https://github.com/felis/USB_Host_Shield_2.0
IMPORTANT!!!
To use this library with the official Arduino ADK uncomment the following line in avrpins.h:
#define BOARD_MEGA_ADK
"OSCOKIRQ failed to assert" generally happens when the Max IC inside the board is not working properly. This can happen in two scenarios
The Maxim IC is not getting enough power. (In this case, try connecting an external power source to your board)
There is some problem in the circuit around Maxim IC. If this is the case, then you might have to replace the board.
So first try connecting an external power source and see if this solves it. Otherwise you might have to replace the board.
Super simple for me (with the same issue), just add a delay before acc.powerOn()
the example I saw added 100, but I decided boot up is fast enough for 500. i.e.
void setup()
{
// set communiation speed
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
delay(500);
acc.powerOn();
}
Related
Is there a possibility how to "overcome" BLE MAC address randomization and detect presence of my own Android phone(s)?
I'm looking for a solution how to detect presence of my phone in close-range to ESP32 without installing something like iBeacon app which would drain my battery.
I've started with example for BLE sniffer which works nice but with MAC randomization on Android it is useless.
Then I moved to the solution using emulation of a HID keyboard. After pairing it, it is nicely reconnecting when the phone comes into the range. Once it is connected I can trigger needed action and then I can turn ESP32 Bluetooth off not to be connected whole time. When I need check the phone again I just can turn the server back on. It would be neat solution but... I need to check more (at least two) phones. I've tried to duplicate BLEServers to swith between or run two simoutinasly but without success - either it is not possible or it is exceeding my knowladge about this BLE advertising/pairing/connecting magic.
Third solution would be to have separate ESP for each phone - doable but only as a last resort
Has somebody solved such task somehow already?
For the keyboard solution I'm using this code found online:
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
#include <driver/adc.h>
BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;
BLEAdvertising *pAdvertising;
BLEServer *pServer;
bool connected = false;
bool restart = false;
class MyCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer){
connected = true;
Serial.println("Connected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(true);
// NEEDED ACTIONS
}
void onDisconnect(BLEServer* pServer){
connected = false;
Serial.println("DisConnected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(false);
restart = true;
}
};
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
BLEDevice::init("Backpack-MeowMeow");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyCallbacks());
pServer->getPeerDevices(true);
hid = new BLEHIDDevice(pServer);
input = hid->inputReport(1); // <-- input REPORTID from report map
output = hid->outputReport(1); // <-- output REPORTID from report map
std::string name = "ElectronicCats";
hid->manufacturer()->setValue(name);
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
hid->hidInfo(0x00,0x02);
BLESecurity *pSecurity = new BLESecurity();
// pSecurity->setKeySize();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
hid->startServices();
pAdvertising = pServer->getAdvertising();
pAdvertising->setAppearance(HID_BARCODE);
pAdvertising->addServiceUUID(hid->hidService()->getUUID());
pAdvertising->start();
hid->setBatteryLevel(7);
//ESP_LOGD(LOG_TAG, "Advertising started!");
//delay(portMAX_DELAY);
}
void loop() {
if(connected){
delay(10);
}
if (restart) {
restart = false;
pAdvertising->start();
}
delay(50);
}
I am building an internet controlled robot that uses 2 android phones for controlling.
The first phone is connected to Arduino Uno via USB and serves as a 3G shield
The second phone is used to control the whole thing. It sends unassigned byte to the first phone which sends it to Arduino.
The apps I uses on the phones have one problem. The joystick in the app doesn't send a specific command when its in rest. For example when I move it up it sends "1" to the phone connected to the Arduino which drives the motors forward but when I release the joystick it stops sending data however the motors on my robot still spin until I move the joystick down which sends "2" motor.run(RELEASE);
How can I stop the motors if there is no Serial Data available?
This is the code i wrote.
#include <AFMotor.h>
AF_DCMotor motor_left(2, MOTOR12_1KHZ);
AF_DCMotor motor_right(3, MOTOR12_1KHZ);
int ledPin = 13;
int speed_min = 100; //the minimum "speed" the motors will turn - take it lower and motors don't turn
int speed_max = 1000; //the maximum "speed" the motors will turn – you can’t put in higher
int speed_left = speed_max; // set both motors to maximum speed
int speed_right = speed_max;
int command = 0;
void setup ()
{
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
motor_left.setSpeed(255);
motor_left.run(RELEASE);
motor_right.setSpeed(255);
motor_right.run(RELEASE);
motor_left.setSpeed(speed_left); // minimum speed 135 max speed 255
motor_right.setSpeed(speed_right); // minimum speed 135 max speed 255
}
void loop() {
if (Serial.available() > 0);
byte command = Serial.read();
if (command == 1)
{
Serial.println("Move Forward");
digitalWrite(ledPin, HIGH);
motor_left.run(FORWARD);
}
if (command == 2)
{
Serial.println("Stop");
digitalWrite(ledPin, LOW);
motor_left.run(RELEASE);
}
}
So basically it should do nothing if there is no data available.
Use your code like this, it will help
void loop() {
if (Serial.available() > 0) {
byte command = Serial.read();
if (command == 1) {
Serial.println("Move Forward");
digitalWrite(ledPin, HIGH);
motor_left.run(FORWARD);
} else if (command == 2) {
Serial.println("Stop");
digitalWrite(ledPin, LOW);
motor_left.run(RELEASE);
} else {
//put your code to stop Motor
}
}
}
I've run into some weird behaviour and looks like I can't find an answer. I've written some simple code to control a servo motor via bluetooth using my phone.
#include <Servo.h>
#include "SoftwareSerial.h";
int servoPin = 2;
int bluetoothTx = 11;
int bluetoothRx = 10;
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
Servo myservo;
char unChar;
String readString;
void setup() {
Serial.begin(9600);
bluetooth.begin(115200);
delay(100);
bluetooth.begin(9600);
myservo.attach(servoPin, 800, 2200);
}
void loop() {
if (bluetooth.available()) {
unChar = bluetooth.read();
Serial.println(unChar);
if (unChar == 'A') {
motor();
}
}
}
void motor() {
delay(15);
while (bluetooth.available()) {
char c = bluetooth.read();
readString += c;
}
if (readString.length() > 0) {
Serial.println(readString.toInt());
myservo.write(readString.toInt());
readString = "";
}
}
For android, I used the MIT App Inventor to make a basic slider.
I'm using an Arduino Mega 2560, Power HD High-Torque High-Voltage Digital Servo 1218TH and a Bluetooth Mate Silver RN-41.
Everything works fine with the exception of the servo stuttering while dragging the slider on the phone. That is one small problem. The weird behaviour appears when I comment or delete my code in the arduino loop. The servo still stutters on its place when I play with the slider. What causes this behaviour?
Try to re-adjust the delay time after delete comment, it happens because add debug log inside the loop needs time to show up. In other words, that comment inside the loop has an impact on delay time.
I got the problem, that the following code ain't multitasked.
How can I realize that?
My code works at the moment as follow:
I start my Android app, there I confirm the USB request.
After the press of the "start button", my app sends a byte array to my arduino board.
The problem is that "stepper2(ingredient1value);" can only start when "stepper1..." finished.
I know that arduino ain't the right plattform for multithreading, but I saw some solutions, but I can't integrated them into my code.
Thanks for helping me!
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define VALUE_OFF 0x0
#define VALUE_ON 0x1
#define COMMAND_LED 0x2
#define TARGET_PIN_12 0x12
int stepperPin1 = 9;
int stepperPin2 = 10;
int stepperPin3 = 11;
int stepperPin4 = 12;
int stepperPin5 = 13;
//change this to the number of steps on your motor
#define STEPS 48
AndroidAccessory acc("Manufacturer", "Model", "Description", "1.0", "URI","Serial");
byte ingredient1value, ingredient2value, ingredient3value, ingredient4value, ingredient5value;
byte rcvmsg[8];
void setup() {
Serial.begin(115200);
pinMode(stepperPin1, OUTPUT);
pinMode(stepperPin2, OUTPUT);
pinMode(stepperPin3, OUTPUT);
pinMode(stepperPin4, OUTPUT);
pinMode(stepperPin5, OUTPUT);
acc.powerOn();
}
void stepper1(int turns1){
for(int i=0;i<turns1*STEPS;i++){
digitalWrite(stepperPin1, HIGH);
delayMicroseconds(800);
digitalWrite(stepperPin1, LOW);
delayMicroseconds(800);
}
}
void stepper2(int turns2){
for(int i=0;i<turns2*STEPS;i++){
digitalWrite(stepperPin2, HIGH);
delayMicroseconds(800);
digitalWrite(stepperPin2, LOW);
delayMicroseconds(800);
}
}
void stepper3(int turns3){
for(int i=0;i<turns3*STEPS;i++){
digitalWrite(stepperPin3, HIGH);
delayMicroseconds(800);
digitalWrite(stepperPin3, LOW);
delayMicroseconds(800);
}
}
void stepper4(int turns4){
for(int i=0;i<turns4*STEPS;i++){
digitalWrite(stepperPin4, HIGH);
delayMicroseconds(800);
digitalWrite(stepperPin4, LOW);
delayMicroseconds(800);
}
}
void stepper5(int turns5){
for(int i=0;i<turns5;i++){
digitalWrite(stepperPin5, HIGH);
delay(1000);
digitalWrite(stepperPin5, LOW);
delay(1000);
}
}
void loop() {
delay(50);
if (acc.isConnected()) {
acc.read(rcvmsg, sizeof(rcvmsg), 1);
if (rcvmsg[0] == COMMAND_LED && rcvmsg[1] == TARGET_PIN_12) {
byte value = rcvmsg[2];
if (value == VALUE_ON){
ingredient1value=rcvmsg[3] ;
ingredient2value=rcvmsg[4] ;
ingredient3value=rcvmsg[5] ;
ingredient4value=rcvmsg[6] ;
ingredient5value=rcvmsg[7] ;
stepper1(ingredient1value);
stepper2(ingredient2value);
stepper3(ingredient3value);
stepper4(ingredient4value);
stepper5(5);
}
}
}
}
One approach could be to avoid delay() (or delayMicroseconds()) in your code and replace these code passages with code patterns, which does not interrupt the main loop and allow the Arduino to execute commands in specific frequencies or times.
Here is an example how you can execute a function every second without using delay() (and without block other commands, which should be executed with a higher frequency):
// 1 sec. frequency
unsigned long interval=1000; // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.
// 3 sec. frequency
unsigned long interval1=3000; // the time we need to wait
unsigned long previousMillis1=0; // millis() returns an unsigned long.
void setup() {
//...
}
void loop() {
if ((unsigned long)(millis() - previousMillis) >= interval) {
previousMillis = millis();
// every second
// ...
}
if ((unsigned long)(millis() - previousMillis1) >= interval1) {
previousMillis1 = millis();
// every third second
// ...
}
// other CMD's...
}
EDIT:
This approach does not integrate a real multi-task, but gives you the possibility to integrate a pseudo-parallelism in your project.
I added a second condition (execution every third second)to exemplify the principle.
Basically answer by user3704293 is correct:
For each action you want to perform regularly, create a variable
that holds the interval between actions, in milliseconds.
Create a second variable that will hold the time, when it was last
triggered.
Create an if-statement that checks how much time has passed since last trigger, and triggers the action if time is greater than the interval
Write time of last trigger into the variable
However this naive algorithm with fail if Arduino is left running for more than a month. The millis(); function will reach maximum value in roughly 50 days, and rollover back to zero. Once that happens, you code will no longer trigger.
Please look into this guide on arduino playground, it's the cause of much confusion for many hobbyists. It probably won't matter for your project, but it may for others.
If your project gets more complicated, it would benefit from having a Real scheduler, instead of having you reinvent the wheel. It's like a small operating system that manages several tasks for you. Some are available as Arduino libraries. DuinOS is a good one to look at, it's based on FreeRTOS - very popular, you will see it everywhere. If you learn how to use it, that would serve you well in the future.
If you are short on program memory, use Protothreads instead. There are other alternatives, but these are good places to start.
Finally if you need scheduling on a calendar date, you would need to connect a Real Time Clock, take a look at the Time library
I'm trying to communicate between Arduino Mega Adk (ADK 2011) and android device.
Something goes ok, but something goes completely wrong.
Transfer data from Android to Arduino via acc.read from Arduino side works fine.
But when i try to send some bytes from Arduino to Android - something strange happens.
First of all here is Arduino sketch:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define COMMAND_LED 0x2
#define TARGET_PIN_18 0x12
#define TARGET_PIN_19 0x13
#define V_ON 0x1
#define V_OFF 0x0
#define PIN_18 18
#define PIN_19 19
#define INPUT_PIN 30
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Ololo device board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte rcvmsg[3];
byte sndmsg[3];
int buttonState = 0;
void setup();
void loop();
void led_setup(){
pinMode(PIN_18, OUTPUT);
pinMode(PIN_19, OUTPUT);
pinMode(INPUT_PIN, INPUT);
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
led_setup();
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
sndmsg[0] = 0x2;
sndmsg[1] = 0x1;
sndmsg[2] = 0x1;
int len = acc.write(sndmsg, 3);
digitalWrite(PIN_19, HIGH);
}
else {
//Nothing here for test
}
}
//usefull test for button
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
digitalWrite(PIN_19, HIGH);
}
else {
digitalWrite(PIN_19, LOW);
}
}
Ok. When acc.write() is executed it takes up to ~1 second to transfer data to android. And this time doesn't depend on number of bytes in sndmsg. Only if i execute acc.write(sndmsg,0) (sending 0 bytes) - everything goes fast.
That is a little bit disturbing. I've tried to change board to another one but have got the same result.
Any advices? may be that is a common bug, but there is no such much information in web.
UPD:
Wrote some very simple code, that only sends 3 bytes via acc.write.
here it is:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Demokit board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte msg[3];
unsigned long time;
void setup();
void loop();
void led_setup(){
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
Serial.print("\r\nis Connected");
msg[0] = 0x1;
msg[1] = 0x1;
msg[2] = 0x1;
//Serial.print("\r\nSending");
time = millis();
Serial.print ("\r\nBefore write\r\n");
Serial.print (time);
acc.write(msg, 3);
time = millis();
Serial.print("\r\nAfter write: \r\n");
Serial.print (time);
//delay(500);
}
}
And it's debug output is:
is Connected
Before write
6983
After write:
10958
is Connected
Before write
10958
After write:
14491
is Connected
and so on. So on some reasons acc.write takes a lot of time and there is no data in the android app.
New UPD (19.01.2015):
Today i've performed some experiments. Here are results.
First, i've looked into AndroidAccessory.cpp and found write function:
int AndroidAccessory::write(void *buff, int len)
{
usb.outTransfer(1, out, len, (char *)buff);
return len;
}
Ok, then i looked into usb host shield library and found there usb.cpp with outTransfer fucntion, that returns error code if ouccured and 0x00 if everything is ok.
So i modified write function to return an error code instead of lenght, like this:
int AndroidAccessory::write(void *buff, int len)
{
byte rcode;
rcode = usb.outTransfer(1, out, len, (char *)buff);
return int(rcode);
}
and recived "4" as result.
According to MAX3421Econstants.h it is hrNAK (0x04) error code.
Any ideas? Looks like accessory does not recive NAKs from Android and write fails as a result.
Situation update:
Did some research. There is a hell of NAK's when accessory is connected. Here is dump from usb connector:
i found the solution. And it is very simple - i didn't setup communication with accessory correctly.
This is not an Arduino problem. Arduino works fine.
It is just how android interacts with android accessory.
So, results:
When AndroidAccessory is plugged to Android and Android haven't setup
communication with the accessory yet, Android OS will send a lot of
USB NAKs to the accessory and this is normal.
You must be careful
during setuping communication with the accessory. If you make some
mistakes, you can receive same situation: Probably possible to write
to the accessory, but accessory isn't possible to write to the
android.
If UsbManager opens accessory correctly, it stops sending
NAKs and starts recieve data from arduino.
It is a little bit strange for me, because it was really hard to found a problem: i have an application, written according to this manual: http://developer.android.com/guide/topics/connectivity/usb/accessory.html But, because i'm not very familiar with android, it seems that i've done some mistakes and receive strange behavior:
i was able to write to arduino
i was able to retrive information about arduino as android accessory
it was possible to ask for permissions
but when arduino tries to write to android, it recievs a lot of NAKs
So i decided to rewrite program in more simple way, just with one function and tried to do it in right way. And after some debugging it finally started to work as i want.
So thank everyone, who spend time for reading this.
Bonus: dump of normal packet, ended with EOP not NAK
UPD 26.01.2015:
I found problem and it was in my android code.
here is explanation:
Android developer's manual said that function, which set up communication with accessory must start it's own thread in which all communications with input and output streams are held. Smth like this:
private void openAccessory() {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(mAccessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryThread");
thread.start();
}
}
I really messed this thing up. Forgot about creating new thread in openAccessory function and tried to do it in different place. And recieve a hell of NAK's. Then i've changed my code and add some debug-like run() function like this:
public void run() {
final byte[] buffer = new byte[16384];
int ret = 0;
int i = 0;
while (i<50) {
try {
ret = mInputStream.read(buffer);
i++;
Thread.sleep(500);
} catch (IOException e) {
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And until this run method exists (while i < 50) android reads arduino correctly. And when thread ends up (i > 50) - Arduino starts to readout Error Code 4 (NAK) from Android.
That's all folks.