Closed dsyleixa closed 5 years ago
What are you trying to do? What is the demo.ini program? What do your data values represent? What code produces these values? Can you plot the values in Veusz?
Nunchuk demo.ino, not demo.ini !!! https://github.com/infusion/Fritzing/blob/master/Nunchuk/demo.ino
perhaps this issue report is somehow similiar to te one reported here, but not for sure, though: https://github.com/infusion/Fritzing/issues/2
We had this problem already twice and one user sent me an Arduino Due to replicate the problem. The thing is, the Due is too fast and you need to slow it down. In the code you can find several positions with delays. Unfortunately, I couldn't find a clean solution yet and commented all occurrences out. The first step should be to uncomment all delays and test it. After that you can comment in the delays and test what delay is really needed to make it work
I tried the nunchuk code with uncommented delay(1) in the nunchuk.h, but without any effect, still not functional, neither for the Due nor for the Adafruit M4. IMO it cannot be a matter of i2c clock, because all my i2c devices work fine with all my ARM cores, both at 100kHz and at 400kHz. Just the Nunchuk ist malfuncional. Perhaps it's a clock-stretching issue.
PS: 1 user was proposing to add ack read sequences, but it's from a PIC code which I cannot port to Arduinish - still sceptical if that would solve this issue actually, though:
might that help perhaps?
update: I just re-tested both the original nunchuk.h and the revised one by un-commented delay(1) by a extented demo program: Same reading errors as before, but the nunchuk is detected correctly at 0x52:
#include <Wire.h>
#include "Nunchuk.h"
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Serial() started");
Wire.begin();
Wire.setClock(100000ul);
Serial.println("Wire() started");
// nunchuk_init_power(); // A1 and A2 is power supply
// scanning for Nunchuk address 0x52
Serial.println("Scanning for Nunchuk");
Wire.beginTransmission(0x52);
int error = Wire.endTransmission();
if (error == 0) {
Serial.println("Nunchuk found at 0x52");
}
else {
Serial.print("Nunchuk error: ");
Serial.println(error);
}
Serial.println(); Serial.println();
nunchuk_init();
}
void loop() {
if (nunchuk_read()) {
// Work with nunchuk_data
nunchuk_print();
}
delay(10);
}
Serial output for the uncommented version:
Serial() started
Wire() started
Scanning for Nunchuk
Nunchuk found at 0x52
-127,36,-384,-512,-512,1,1
0,46,-12,40,-132,1,1
-127,-128,-512,-512,-512,1,1
-127,-128,-512,-512,-512,1,1
128,127,511,511,511,0,0
128,127,508,508,-10,0,1
0,-118,194,215,196,0,0
99,-99,-9,403,-387,0,1
-86,-2,-10,4,-4,1,0
49,53,199,-275,392,0,1
-2,100,-385,-9,-347,1,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,-172,-512,-512,1,1
-127,-128,-512,-512,-512,1,1
-127,-128,144,-384,-512,1,1
-3,-1,187,-11,41,0,0
-127,-128,-512,-512,-512,1,1
-127,-128,-512,-512,-512,1,1
-127,127,511,511,511,0,0
128,127,511,511,509,0,1
2,-1,-472,195,214,0,1
-68,98,-393,-11,400,0,0
-2,-87,-5,-9,5,0,0
-117,48,212,198,-273,1,0
-98,-3,402,-386,-12,0,1
-1,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
128,127,511,511,511,0,0
(I HATE that annoying github editor for formatting !!)
Thanks for providing the update. Did you uncomment all delays? Did you try to increase the time, like delay(10) or so? Without a scope it's hard to tell if the timing is right.
yes, uncommented all // delay(1)
are there more delays to uncomment?
The delayMicroseconds are crucial I think. At least with these values the Nunchuk worked for the Due I have
YES !! 8-)
uncommenting the delayMicroseconds did it!
I then out-commented again the delay(1), and it still works AFAICS
this is the latest version which works currently for me (no warranty though ;) )
/**
* @license Nunchuk Arduino library v0.0.1 16/12/2016
* http://www.xarg.org/2016/12/arduino-nunchuk-library/
*
* Copyright (c) 2016, Robert Eisele (robert@xarg.org)
* Dual licensed under the MIT or GPL Version 2 licenses.
**/
#ifndef NUNCHUK_H
#define NUNCHUK_H
#include <Wire.h>
// Calibration accelerometer values, depends on your Nunchuk
#define NUNCHUK_ACCEL_X_ZERO 512
#define NUNCHUK_ACCEL_Y_ZERO 512
#define NUNCHUK_ACCEL_Z_ZERO 512
// Calibration joystick values
#define NUNCHUK_JOYSTICK_X_ZERO 127
#define NUNCHUK_JOYSTICK_Y_ZERO 128
// Whether to disable encryption. Enabling encryption means that every packet must be decrypted, which wastes cpu cycles. Cheap Nunchuk clones have problems with the encrypted init sequence, so be sure you know what you're doing
#define NUNCHUK_DISABLE_ENCRYPTION
// Print debug information instead of a CSV stream to the serial port
// #define NUNCHUK_DEBUG
// The Nunchuk I2C address
#define NUNCHUK_ADDRESS 0x52
#if ARDUINO >= 100
#define I2C_READ() Wire.read()
#define I2C_WRITE(x) Wire.write(x)
#else
#define I2C_READ() Wire.receive()
#define I2C_WRITE(x) Wire.send(x)
#endif
#define I2C_START(x) Wire.beginTransmission(x)
#define I2C_STOP() Wire.endTransmission(true)
uint8_t nunchuk_data[6];
uint8_t nunchuk_cali[16];
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) // Only Arduino UNO
/**
* Use normal analog ports as power supply, which is useful if you want to have all pins in a row
* Like for the famous WiiChuck adapter
* @see https://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
*/
static void nunchuk_init_power() {
// Add power supply for port C2 (GND) and C3 (PWR)
PORTC &= ~_BV(PORTC2);
PORTC |= _BV(PORTC3);
DDRC |= _BV(PORTC2) | _BV(PORTC3);
delay(100);
}
#endif
/**
* Initializes the Nunchuk communication by sending a sequence of bytes
*/
static void nunchuk_init() {
// Change TWI speed for nuchuk, which uses Fast-TWI (400kHz)
Wire.setClock(400000);
// delay(1);
#ifdef NUNCHUK_DISABLE_ENCRYPTION
I2C_START(NUNCHUK_ADDRESS);
I2C_WRITE(0xF0);
I2C_WRITE(0x55);
I2C_STOP();
// delay(1);
I2C_START(NUNCHUK_ADDRESS);
I2C_WRITE(0xFB);
I2C_WRITE(0x00);
I2C_STOP();
// delay(1);
#else
I2C_START(NUNCHUK_ADDRESS);
I2C_WRITE(0x40);
I2C_WRITE(0x00);
I2C_STOP();
// delay(1);
#endif
#ifdef NUNCHUK_DEBUG
Serial.print("Ident: "); // 0xA4200000 for Nunchuck, 0xA4200101 for Classic, 0xA4200402 for Balance
I2C_START(NUNCHUK_ADDRESS);
I2C_WRITE(0xFA);
I2C_STOP();
Wire.requestFrom(NUNCHUK_ADDRESS, 6);
for (uint8_t i = 0; i < 6; i++) {
if (Wire.available()) {
Serial.print(I2C_READ(), HEX);
Serial.print(" ");
}
}
I2C_STOP();
Serial.println("");
delay(100); // Wait for serial transfer, before loop()ing
#endif
}
/**
* Decodes a byte if encryption is used
*
* @param x The byte to be decoded
*/
static inline uint8_t nunchuk_decode_byte(uint8_t x) {
#ifdef NUNCHUK_DISABLE_ENCRYPTION
return x;
#else
return (x ^ 0x17) + 0x17;
#endif
}
/**
* Central function to read a full chunk of data from Nunchuk
*
* @return A boolean if the data transfer was successful
*/
static uint8_t nunchuk_read() {
uint8_t i;
Wire.requestFrom(NUNCHUK_ADDRESS, 6);
delayMicroseconds(10);
for (i = 0; i < 6 && Wire.available(); i++) {
nunchuk_data[i] = nunchuk_decode_byte(I2C_READ());
}
I2C_START(NUNCHUK_ADDRESS);
I2C_WRITE(0x00);
delayMicroseconds(100);
I2C_STOP();
return i == 6;
}
/**
* Checks the current state of button Z
*/
static uint8_t nunchuk_buttonZ() {
return (~nunchuk_data[5] >> 0) & 1;
}
/**
* Checks the current state of button C
*/
static uint8_t nunchuk_buttonC() {
return (~nunchuk_data[5] >> 1) & 1;
}
/**
* Retrieves the raw X-value of the joystick
*/
static uint8_t nunchuk_joystickX_raw() {
return nunchuk_data[0];
}
/**
* Retrieves the raw Y-value of the joystick
*/
static uint8_t nunchuk_joystickY_raw() {
return nunchuk_data[1];
}
/**
* Retrieves the calibrated X-value of the joystick
*/
static int16_t nunchuk_joystickX() {
return (int16_t) nunchuk_joystickX_raw() - (int16_t) NUNCHUK_JOYSTICK_X_ZERO;
}
/**
* Retrieves the calibrated Y-value of the joystick
*/
static int16_t nunchuk_joystickY() {
return (int16_t) nunchuk_joystickY_raw() - (int16_t) NUNCHUK_JOYSTICK_Y_ZERO;
}
/**
* Calculates the angle of the joystick
*/
static float nunchuk_joystick_angle() {
return atan2((float) nunchuk_joystickY(), (float) nunchuk_joystickX());
}
/**
* Retrieves the raw X-value of the accelerometer
*/
static uint16_t nunchuk_accelX_raw() {
return ((uint16_t) nunchuk_data[2] << 2) | ((nunchuk_data[5] >> 2) & 3);
}
/**
* Retrieves the raw Y-value of the accelerometer
*/
static uint16_t nunchuk_accelY_raw() {
return ((uint16_t) nunchuk_data[3] << 2) | ((nunchuk_data[5] >> 4) & 3);
}
/**
* Retrieves the raw Z-value of the accelerometer
*/
static uint16_t nunchuk_accelZ_raw() {
return ((uint16_t) nunchuk_data[4] << 2) | ((nunchuk_data[5] >> 6) & 3);
}
/**
* Retrieves the calibrated X-value of the accelerometer
*/
static int16_t nunchuk_accelX() {
return (int16_t) nunchuk_accelX_raw() - (int16_t) NUNCHUK_ACCEL_X_ZERO;
}
/**
* Retrieves the calibrated Y-value of the accelerometer
*/
static int16_t nunchuk_accelY() {
return (int16_t) nunchuk_accelY_raw() - (int16_t) NUNCHUK_ACCEL_Y_ZERO;
}
/**
* Retrieves the calibrated Z-value of the accelerometer
*/
static int16_t nunchuk_accelZ() {
return (int16_t) nunchuk_accelZ_raw() - (int16_t) NUNCHUK_ACCEL_Z_ZERO;
}
/**
* Calculates the pitch angle THETA around y-axis of the Nunchuk in radians
*/
static float nunchuk_pitch() { // tilt-y
return atan2((float) nunchuk_accelY(), (float) nunchuk_accelZ());
}
/**
* Calculates the roll angle PHI around x-axis of the Nunchuk in radians
*/
static float nunchuk_roll() { // tilt-x
return atan2((float) nunchuk_accelX(), (float) nunchuk_accelZ());
}
/**
* A handy function to print either verbose information of the Nunchuk or a CSV stream for Processing
*/
static void nunchuk_print() {
#ifdef NUNCHUK_DEBUG
Serial.print("joy: ");
Serial.print(nunchuk_joystickX(), DEC);
Serial.print(", ");
Serial.print(nunchuk_joystickY(), DEC);
Serial.print(" acc:");
Serial.print(nunchuk_accelX(), DEC);
Serial.print(", ");
Serial.print(nunchuk_accelY(), DEC);
Serial.print(", ");
Serial.print(nunchuk_accelZ(), DEC);
Serial.print(" but:");
Serial.print(nunchuk_buttonZ(), DEC);
Serial.print(", ");
Serial.print(nunchuk_buttonC(), DEC);
Serial.print("\n");
#else
Serial.print(nunchuk_joystickX(), DEC);
Serial.print(",");
Serial.print(nunchuk_joystickY(), DEC);
Serial.print(",");
Serial.print(nunchuk_accelX(), DEC);
Serial.print(",");
Serial.print(nunchuk_accelY(), DEC);
Serial.print(",");
Serial.print(nunchuk_accelZ(), DEC);
Serial.print(",");
Serial.print(nunchuk_buttonZ(), DEC);
Serial.print(",");
Serial.print(nunchuk_buttonC(), DEC);
Serial.print("\n");
#endif
}
#endif
thanks a lot for your feedback!
Update: un-commenting just the delayMicroseconds also seems to work for the Adafruit M4, too.
PS, what do you think about reading the acks for wire transmissions before further processing (instead of adding delays) ?
YES! :) Could you please check if the following works on your Adafruit M4:
#if defined(__SAM3X8E__)
Serial.println("Yes it works");
#endif
This should identify the arm processor so that the microdelay can be added selectively. Did you test reading the acks before processing instead of adding delays?
not sure if @dsyleixa is the forum user that i wrote for, but in the forum he acknowledged that removing those microdelays did the trick ... maybe in those nunchucks is a microcontroller like an atmega, that don't like large (25ms in atmega case) clock stretching ... just a thought based on experience with atmegas :)
@mindforger Thanks for these thoughts. Do you see a way to solve this issue without delaying? (BTW: what forum?)
YES! :) Could you please check if the following works on your Adafruit M4:
#if defined(__SAM3X8E__) Serial.println("Yes it works"); #endif
This should identify the arm processor so that the microdelay can be added selectively. Did you test reading the acks before processing instead of adding delays?
the Adafruit is ATSAMD51, but it is possible to define:
#ifdef SAMD_SERIES
PS, yes it's me, babe :D
from THIS forum: https://www.roboternetz.de/community/threads/73249-Wii-Nunchuck-an-Arduino?p=651344&viewfull=1#post651344 ;)
Do you see a way to solve this issue without delaying?
not really, in case of atmegas its an issue with licensing i2c from phillips in the past, so they used smbus, which is pretty much the same but with additional context and a max clock stretch time of 25ms
i had an issue with an i2c converter chip doing very long stretches during input accumulation, resulting in the atmega forcing clocks out chokeing the chip logic
Is SAMD_SERIES
defined on the Due or just the Adafruit board? If this symbol can be used to distinguish between AVR and ARM, it would be a quite pretty fix for the moment. I'm not sure if we can change the clock stretching using Wire lib, that would be a nice test.
Edit: Found it! Wire.setClockStretchLimit(x)
(x is in µs). Could you please test if the original nunchuk.h file works when you change the clock stretch limit?
yes, for either ARM board I'm using it for adding the sprintf to float formatting to all my ARM boards.
edit, correction: in my latest test on a different platform, SAMD_SERIES didn't include the Due any more, just M0 and M4.
Okay, added #ifdef SAMD_SERIES
.
YES, tested: OK! (y)
update:
Although the last test was supposed to work for the Due by the directive
#ifdef SAMD_SERIES
now in a different environment it did no longer, surprisingly, but just for the M4. Perhaps my earlier attempts with this have been faulty somehow.
So I would suggest to exchange that by
#if defined (SAMD_SERIES) || defined (__SAM3X8E__)
which produces correct compilations safely for either SAM target.
Unfortunately, my Due again is currently no longer functional with the Nunchuk any more, all values are freezing, no idea why. The M4 is working fine though.
update2:
also
#ifdef SAM
seems to work stable for either SAM target.
Does the SAM
check work on all SAM targets? Is this a legitimate solution for all platforms?
Due to an updated information of pert/per123, and according to my tests with different programs: yes.
Unfortunately I can no longer test the nunchuk.h with the Due as it fails now (even with completely outcommented "#if defined()
), but all my other test programs could verify this information.
https://forum.arduino.cc/index.php?topic=609814.msg4135586#msg4135586
"All ARMs" covers a lot of ground. I don't know of a standardized macro to identify any microcontroller that uses an ARM core. However, if you want a single macro that will match the Due, any of the Arduino SAMD Boards, and any of the Adafruit SAMD boards, as well as any other of the SAM chips, you can use the SAM macro.
I don't have any informations yet about since which IDE version it was implemented, though.
Merci! It's changed :) What means it does not work anymore?
again the output values are blocking and freezing, not even the repetitively changing artefacts any more.
During testing, I had falsly connected the nunchuk wrong way round:
SCL-SDA-3V3-GND instead of
GND-3V3-SDA-SCL,
by having correct Arduino-i2c 2.2k pullups though,
so I first thought it might have caused a short-cut damage, but other i2c devices (MPU6050, CMPS11) are still working correctly.
But also the nunchuk still runs quite fine with my M4.
Could you figure out what command is blocking? Hmm, that's super strange. I first thought maybe you burned the Nunchuk, since it is quite sensitive for the supplied voltage. Even if you provide 3V3 for the power line, the I2C wires still provide 5V. You only got one Due and one Nunchuk, right?
the power input by my Arduinos is 3v3, not 5V, same to i2c signal voltage. But yes, I have 1 Due, 1 nunchuk, 1 M4. Perhaps I once might have a chance to borrow another nunchuk or another Due, but not right now.
Yes, the power line is 3v3. But the clock line is 5V. But I connected it also wrong often enough and it still works. You should figure out what part of the code is blocking and not working anymore
I have to disagree: the Due signal levels for i2c are 3v3, and the pullups pull up to 3v3 too! No idea how to explore where the code is blocking... But actually I need it for my M4, and here it's fine anyway
Okay, my bad
hi, the Nunchuk demo.ino example code works with MEGA and UNO but not with Arduino Due (M3) and/or M4 core. Here I get repetitive readings like
the repetitive changes occur without applying any action and don't even change a thing in case of button press and/or Joystick moves etc.
I tested both with an Arduino Due (Original) with M3 (SAM3X8E) and an Adafruit Feather M4 (ATSAMD51) by completely identical Serial() outputs. Arduino IDE 1.8.8 Adafruit M4: 1.3.0 (latest) Arduino Due 1.6.12 (latest)
i2c bus is ok, different tests with MPU6050 or ADS1115 or OLED SSD1306 or CMPS11/12 are all fine, and by a i2c scanner the nunchuk is detected at 0x52 correctly (both aat 100kHz and 400kHz bus clock).
How can that issue be fixed?