Low-level manipulation of the Motor Shield

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
The_lone1
 
Posts: 6
Joined: Tue Nov 05, 2013 5:31 pm

Low-level manipulation of the Motor Shield

Post by The_lone1 »

I'm looking at the possibility of integrating the v2 motor shield into the LasaurGrbl code (read: horribly hacking them until they play nice. If you want to know why, see the end of this post), and as such I have a few questions.

After writing out an incredibly verbose introduction to my first question, I suddenly realised the answer. However, I would like to check my answer: the reason the default slave address of the board is 0x60 and not 0x40 (which is the PWM chip default) is due to address select pin 5 (A5, which isn't broken out on the motor shield) being tied high; and that I was confusing myself, as despite knowing that I2C addresses are 7 bits long I was counting the R/W bit shown in the datasheet as part of the address (please point out if I've just made another face-palm-worthy mistake).

My second question concerns the onestep function. In calling onestep, the two values, ocra and ocrb (which I assume are used to control the coil power to facilitate microstepping), are set to a value chosen from the array microstepcurve, and are passed to the PWM pins thusly:

Code: Select all

MC->setPWM(PWMApin, ocra*17);
MC->setPWM(PWMBpin, ocrb*17);
However, the setPWM function coerces the value to the range 0-4096. This means the last 4 (or 2, if using 8 microsteps) values are effectively saturated:

Code: Select all

{0, 25,  50,  74,   98,   120,  141,  162,  180,  197,  212,  225,  236,  244,  250,  253,  255} //microstepcurve
{0, 425, 850, 1258, 1666, 2040, 2397, 2754, 3060, 3349, 3604, 3825, 4012, 4148, 4250, 4301, 4335}//microstepcurve*17
I know the value is truncated because the chip uses 12 bit PWM, but what I would like to know: is there a particular reason ocra and ocrb are multiplied by 17 ( and not, say 16, which seems to give an unsaturated curve)?

For my final question (for now), seeing as the LasaurGrbl code already has some pretty swanky functions that process the G-code (including look-ahead to get smoother acceleration profiles) that are then used by an ISR to generate step-events, (which as far as I can tell, have already taken care of microstepping, although I still need to ask about this), would it not make sense to bypass the motor shield libraries, and just replicate the setPWM and setPin functions (assuming I can figure out how to translate the direction and step bits into values on the microstepping curve, and the latch state)?

**************************************************

For those of you who (can be bothered to read this far|want to know why I'm trying to do this|would like to have a small chuckle at my naïveté/arrogance), I'll tell you a short story:
Whilst bored, and browsing Instructables, I came across the Pocket Laser Engraver. After a brief read, I decided that I would build my own. I went out and bought two disk drives, and stripped out the unneeded gubbins. But instead of buying two stepper drivers as per the instructions, I decided I could save myself some money and get a board that could drive two (or more) stepper motors.
I chose the v2 motor shield, as it was less than the price of 2 EasyDrivers (which were recommended); and since it was an Adafruit product, it'd be high quality, and well supported. It was only when I had received, soldered, and tested my brand new motor shield, that I decided to delve into the LasaurGrbl code, to see where I would make the quick-and-easy changes which would allow the whole thing to work. At this point, I realised that there was no way I could simply reassign some pins, or change an I2C address.
In the true spirit of hacking (and only partly to cover up my naïveté/arrogance as a hacker), instead of either giving up, or giving in and buying the parts I should have in the first place, I decided to set out upon the much harder route of gaining a deep enough understanding of both LasaurGrbl and the motor shield to enable me to rewrite one or both of them so they will eventually play nice.
So far, I have figured out that the stepping is done by pulsing PORTB with step and direction bits in an ISR, and that if I can figure out how to translate 6 bits into the PWM and latch states used by the motor shield, drop in some I2C, and fiddle with the timers to allow for the increased delay that will ensue, it Might. Just. Work.

tl;dr:
I really should have paid closer attention to the instructable; now I have to work a lot harder, but will possibly end up with something even better.

User avatar
adafruit_support_bill
 
Posts: 88088
Joined: Sat Feb 07, 2009 10:11 am

Re: Low-level manipulation of the Motor Shield

Post by adafruit_support_bill »

You are correct in your analysis of the addressing. I'll look into the *17 question.

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm

Re: Low-level manipulation of the Motor Shield

Post by adafruit »

hmm good point about the *17 thing, what happens if you change it to 16 in your code? does it work better?

The_lone1
 
Posts: 6
Joined: Tue Nov 05, 2013 5:31 pm

Re: Low-level manipulation of the Motor Shield

Post by The_lone1 »

At this point in the endeavour, this is my code, a simple test program mostly to check the wiring, and get the basics working:

Code: Select all

/*
Max steps test.
 Designed to find the maximum number of microsteps between two limit switches
 Uses the Adafruit Motor Shield, v2
 ---->	http://www.adafruit.com/products/1438
 */

//========================================
// Includes
//========================================
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"

//========================================
//Static Definitions
//========================================

//Create AFMS v2
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

//assign Stepper to port #2 (M3 & M4)
Adafruit_StepperMotor *stepper_x = AFMS.getStepper(200,2);

//sense pins:
int x_lim1 = 6; //"backwards" limit
int x_lim2 = 7; //"forwards" limit
//step counting
//int oneStep = 0;
int microStep = 0;

void setup() {
  Serial.begin(9600);
  AFMS.begin();
  stepper_x->setSpeed(1);// (nice and slow)
  pinMode(x_lim1,INPUT_PULLUP);
  pinMode(x_lim2,INPUT_PULLUP);
  Serial.println("Stepper Limit switch testing");
  Serial.println("Resetting position");
  while(!digitalRead(x_lim1)) {
    stepper_x->onestep(BACKWARD, MICROSTEP);
  }
  Serial.println("Beginning test...");
}

void loop() {
  while(digitalRead(x_lim2)) {
    stepper_x->onestep(FORWARD, MICROSTEP);
    microStep++;
  }
  Serial.print("Forward Microsteps: ");
  Serial.println(microStep);
  microStep = 0;
  
  while(!digitalRead(x_lim1)) { //x_lim1 is push-to-break
    stepper_x->onestep(BACKWARD, MICROSTEP);
    microStep++;
  }
  Serial.print("Backward Microsteps: ");
  Serial.println(microStep);
  microStep = 0;
}
After two frustrating hours trying to get the COM port to reappear (which it did after plugging in the Uno with all Arduino software uninstalled - kinda counter-intuitive), I finally got around to testing three versions of the library code:

Code: Select all

ocra*17 //original
ocra*16 // gives range 0-4080
(ocra+1)*16 // shifts range to 16-4096
Admittedly, the above test code is very simple, but in all three cases, the code reported 3644 +/- 1 microsteps in both directions, and no discernable changes in the performance of the stepper (same noise, approx same speed).

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”