I have been trying for the past several hours to get my board to communicate with the Adafruit V2 Motor shield. I have everything connected precisely as shown in this tutorial but is still does not work. Adafruit includes a few crafted implementation and header files to use their board. They even provide a sample use-case by way of a sketch example! This is the code I used, but still nothing worked.
I decided to debug the code and find out exactly what is happening. I went from file to file as I determined what was working and what was not. I went from Adafruit's files to wire.c and then finally I found the problem in twi.c.
As it turns out, this loop in the code is never returning and spins infinitely.
// wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){
continue;
}
As always though, this code is poorly written and is documented very little so trying to debug this is a mess. I normally program these controllers using code written myself and leave out the Arduino code entirely, for various reasons I must use it for now.
Does anyone have any idea what is happening here? The "twi_state" variable is set earlier in the code to be equal to "TWI_MTX", but is never set elsewhere. That said, I imagine this variable is updated using interrupts, but I did not find any ISRs that may provide deeper insight.
tl;dr : The WIRE library freezes. Specifically, the once the transmission has ended and WIRE.endTransmission() is called, the program freezes in an infinite loop.
Here is the very simple code provided by Adafruit. All it does it make an object defined to represent their shield and initialize it. If one places a print statement following AFMS.begin() you will find that it never prints.
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Stepper test!");
AFMS.begin(); // create with the default frequency 1.6KHz
//AFMS.begin(1000); // OR with a different frequency, say 1KHz
myMotor->setSpeed(10); // 10 rpm
}
void loop() {
Serial.println("Single coil steps");
myMotor->step(100, FORWARD, SINGLE);
myMotor->step(100, BACKWARD, SINGLE);
Serial.println("Double coil steps");
myMotor->step(100, FORWARD, DOUBLE);
myMotor->step(100, BACKWARD, DOUBLE);
Serial.println("Interleave coil steps");
myMotor->step(100, FORWARD, INTERLEAVE);
myMotor->step(100, BACKWARD, INTERLEAVE);
Serial.println("Microstep steps");
myMotor->step(50, FORWARD, MICROSTEP);
myMotor->step(50, BACKWARD, MICROSTEP);
}
Any ideas?
Here is the code trail.
Code from AdaFruit's library included with the shield
void Adafruit_MotorShield::begin(uint16_t freq) {
// init PWM w/_freq
WIRE.begin();
_pwm.begin();
_freq = freq;
_pwm.setPWMFreq(_freq); // This is the maximum PWM frequency
Serial.println("Almost done\n");
for (uint8_t i=0; i<16; i++)
_pwm.setPWM(i, 0, 0);
}
[code]
[b]More AdaFruit Code[/b]
[code]
void Adafruit_PWMServoDriver::begin(void) {
WIRE.begin();
reset();
}
More AdaFruit code
void Adafruit_PWMServoDriver::reset(void) {
write8(PCA9685_MODE1, 0x0);
}
More AdaFruit code
void Adafruit_PWMServoDriver::write8(uint8_t addr, uint8_t d) {
WIRE.beginTransmission(_i2caddr);
WIRE.write(addr);
WIRE.write(d);
WIRE.endTransmission();
Serial.println("Transmission Ended\n"); // *** This never displays
}
Wire.cpp
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
// transmit buffer (blocking)
uint8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
return ret;
}
twi.c ** <-- This is where it fails. The loop code I posted above is in this section **
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 1;
}
// wait until twi is ready, become master transmitter
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MTX;
twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length;
// copy data to twi buffer
for(i = 0; i < length; ++i){
twi_masterBuffer[i] = data[i];
}
// build sla+w, slave device address + w bit
twi_slarw = TW_WRITE;
twi_slarw |= address << 1;
// if we're in a repeated start, then we've already sent the START
// in the ISR. Don't do it again.
//
if (true == twi_inRepStart) {
// if we're in the repeated start state, then we've already sent the start,
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
// We need to remove ourselves from the repeated start state before we enable interrupts,
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
// up. Also, don't enable the START interrupt. There may be one pending from the
// repeated start that we sent outselves, and that would really confuse things.
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
// send start condition
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
// wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){
continue;
}
PORTB |= (1<<0);
_delay_ms(500);
PORTB &= ~(1<<0);
if (twi_error == 0xFF)
return 0; // success
else if (twi_error == TW_MT_SLA_NACK)
return 2; // error: address send, nack received
else if (twi_error == TW_MT_DATA_NACK)
return 3; // error: data send, nack received
else
return 4; // other twi error
}
twi.c (16 KB)
twi.h (1.54 KB)