Note: As of October 25, 2010, all Orangutan X2 versions are shipping with programmable
ATmega1284P microcontrollers instead of the ATmega644P included on older units, and the auxiliary
microcontroller is now an ATmega328P instead of an ATmega168. The ATmega1284P has 128 KB
of program memory, 16 KB of RAM, and 4 KB of EEPROM, and it offers an additional 16-bit timer
(TIMER3). If you have a new Orangutan X2, treat all “mega644” references in this document as
“mega1284” references.
The Orangutan X2 [http://www.pololu.com/catalog/product/738] motor drivers, buzzer, and USB-to-serial interface are
controlled by the auxiliary ATmega168 microcontroller, which is connected to the ATmega644 user controller
via the Serial Peripheral Interface (SPI), a synchronous serial protocol for which the mega644 has a dedicated
hardware module. Once the SPI module is configured correctly, the mega644 can invoke mega168 functions by
sending command packets consisting of one command byte followed by zero or more data bytes. Command bytes
always have an MSB of one while data bytes always have an MSB of zero.
This document explains in great detail the low-level SPI commands used to communicate with the auxiliary
mega168. If you want to get started quickly with your Orangutan X2, you can bypass this detailed documentation
andinsteaduseourhigh-levelCwrapperfunctions [http://www.pololu.com/file/download/
ox2_spi_wrappers_v1_01.zip?file_id=0J20] (12k zip) of these low-level commands. The file SPI.h contains the function
prototypes of the wrappers, along with some convenient #defines; the file SPI.c contains the commented
implementations of the wrappers. By including SPI.h in your project, you will be able to get up and running
quickly with your Orangutan X2. We encourage you to modify these high-level wrapper functions to fit your
specific needs.
Note: Before you can call any of the wrapper functions in SPI.c, you must initialize the mega644’s SPI
hardware module by calling SPIInit(). For examples of how to use these wrapper functions in your Orangutan
X2 projects, please see the sample AVR Studio project files linked from the various Orangutan X2
The mega644 SPI module should be configured as follows:
• SPI enabled
• MSB first
• master mode
• clock polarity 0 (clock line low when idle)
• clock phase 0 (sample on leading ege)
• Maximum frequency: 2.5 MHz (clock/8)
If you have the latest WinAVR [http://winavr.sourceforge.net/] installed (version 20070525 at the time this was
written), the following C code will set up the SPI module, assuming you have your device set as atmega644. If
you are using an older version of WinAVR, you will need to add zeroes to the ends of all of the SPI register/bit
names (e.g. change SPCR to SPCR0, SPSR to SPSR0, SPE to SPE0, etc).
#include <avr/io.h>
// global flag used to help us track when an SPI transmission is in progress
unsigned char SPITransmitting;
void SPIInit()
{
// make the MOSI, SCK, and SS pins outputs
DDRB |= ( 1 << PB5 ) | ( 1 << PB7 ) | ( 1 << PB4 );
// make sure the MISO pin is input
DDRB &= ~( 1 << PB6 );
// set up the SPI module: SPI enabled, MSB first, master mode,
// clock polarity and phase = 0, F_osc/8
SPCR = ( 1 << SPE ) | ( 1 << MSTR ) | ( 1 << SPR0 );
SPSR = 1; // set double SPI speed for F_osc/8
// the previous settings clear the SPIF bit of SPCR, so we use our global
// flag to indicate that this does not mean we are currently transmitting
SPITransmitting = 0;
}
Most commands require data flow in only one direction: from the mega644 to the mega168. This can be achieved
with an SPI transmit command.
void SPITransmit( unsigned char data )
{
if ( SPITransmitting ) // if we really are transmitting
while ( ! ( SPSR & ( 1 << SPIF ))) // wait for completion of
SPDR = data; // begin transmission
SPITransmitting = 1; // flag transmission in progress
}
; // previous transmission
Reading data back from the mega168 is only slightly more complicated since we need to give the mega168 time
(~3us) to prepare the data byte we’re requesting. Once it’s ready we then need to transmit an extra byte since
every SPI transaction has data flow in both directions. As our byte is being sent to the mega168, the data we’re
interested is being sent to us. At the end of the transmission, the value from the mega168 will be in the mega644’s
SPI data register, SPDR. We need an extra function to perform our 3 microsecond delay, so we’ll include an
example here:
static inline void delay_us(unsigned int microseconds) __attribute__((always_inline));
void delay_us(unsigned int microseconds)
unsigned char SPIReceive( unsigned char data ) // data is often a junk byte (e.g. 0)
{
if ( SPITransmitting )
while ( ! ( SPSR & ( 1 << SPIF ))) // wait for completion of
delay_us( 3 ); // give the mega168 time to prepare
SPDR = data; // start bidirectional transfer
while ( ! ( SPSR & ( 1 << SPIF ))) // wait for completion of
// reading SPCR and SPDR will clear SPIF, so we will use our global flag
// to indicate that this does not mean we are currently transmitting
SPITransmitting = 0;
return SPDR;
}
; // previous transmission
// return data
; // transaction
We can now put wrapper functions around these low-level SPI commands to communicate with the mega168. For
instance, here is a command for setting motor 1:
void setMotor1( int speed )
{
// first, we'll prepare our command byte
unsigned char command;
if ( speed > 255 )
speed = 255;
if ( speed < -255 )
speed = -255;
if ( speed >= 0 )
command = 136; // motor 1, forward
else
{
command = 138; // motor 1, reverse
speed = -speed;
}
// the MSB of the speed gets tacked onto the command byte
command |= ( (unsigned char) speed & 0x80 ) >> 7;
We will now elaborate on the low-level SPI commands.
Some commands produce immediate results (e.g. non-acceleration motor commands, all the read commands,
buzzer off) independent of the state of the mega168’s main loop. Others queue up actions to be carried out by the
appropriate handler in the mega168’s main loop (e.g. UART transmit, most buzzer commands, acceleration motor
commands).
The SPI clock can run at up to 2.5 MHz, which corresponds to SPI byte rate of approximately 312 kHz. The
mega168 is designed to be able to accept these bytes as quickly as you are able to send them without losing data
or ignoring commands. However there are a few exceptions:
• If you are sending a command that will cause the mega168 to write to its EEPROM, you will be tying
up the mega168’s main loop for approximately 3.4 ms per EEPROM write. You should not send another
command that will cause an EEPROM write until after the previous write has finished. For example, do
not stream “Store Note” commands to the mega168 any faster than one packet per 10.2 ms. You can send
a command packet that does not cause an EEPROM write immediately following one that does, but realize
that the various handlers in the mega168’s main loop will not get around to that command until after the
EEPROM writes are finished. As such, we recommend that, if possible, you have the mega168 perform any
necessary EEPROM writes during the initialization phase of your program rather than in the middle of some
crucial, time-sensitive phase.
• If you are sending a read command, you must give the mega168 time to load the desired value into its SPI
data register before initiating the SPI transmission that will transfer it to the mega644. The recommended
protocol is to transmit the byte that will tell the mega168 what value is desired (usually this is just the
command byte), wait for the transmission to complete, then wait for an additional 3us before transmitting
another byte (usually this will be a junk data byte or a NULL command). As this last byte is transmitted over
the SPI to the mega168, the desired value is transmitted over the SPI to the mega644. When transmission of
this last byte is complete, the mega644’s SPI data register, SPDR, holds the requested value.
• It doesn’t make sense to stream some commands as quickly as possible to the mega168. For example, you
can send PWM updates to the mega168 at 143 kHz, but given that the fastest PWM frequency you can use is
~20 kHz, such an update rate would be pointless.
In general, you rarely need to worry about having to insert delays between the bytes you’re transmitting over the
SPI; it is up to you to decide what update rate makes the most sense for your particular application.
Note: “motor 1” corresponds to motor bit 0 and “motor 2” corresponds to motor bit 1.
3.a. Motor Commands
3.a.01. Command 214: Set Motor Mode
Effect: This setting determines whether the X2 is running in independent motor mode (i.e. controlling two PWM-
driven motors independently) or in joint motor mode (wired to control only one motor using both drivers operating
in unison). Independent-motor commands are not accepted when running in joint motor mode and joint-motor
commands are not accepted when running in independent motor mode. Setting the mode to joint operation will
synchronize the timers for the two PWMs and set them both based on the settings for motor 1. In general, jointmotor mode uses motor 1 settings only. The X2 defaults to independent motor mode (motor mode bit = 0) after
each hardware reset, so this command really only needs to be sent at the beginning of your program if you wish
to run in joint motor mode (motor mode bit = 1). This setting cannot be stored in EEPROM and hence to operate
in joint mode the mega644 must always send this command after a hardware reset.
If you want to run your X2 in joint motor mode, you should connect one terminal of your motor to the two M1
outputs and the other terminal of your motor to the two M2 outputs.
It is important to note that current sensing is not possible in joint motor mode. The Set Current Limits command
(192—Section 3.a.10) will have no effect in joint motor mode and the Get Average Motor Current command
(216—Section 3.a.12) will not return anything meaningful.
Values sent: motor mode (1 bit)
command byte = 214 | motor mode bit
3.a.02. Command 128: Independent Motor Brake (inB = inA)
Effect: Causes the specified motor to immediately brake high (inA bit = 1) or low (inA bit = 0) with the desired
PWM
Values sent: motor (1 bit), inA (1 bit), PWM (8 bits)
command byte = 128 | (motor bit << 2) | (inA bit << 1) | MSB of PWM
data byte = 7 lower bits of PWM byte
3.a.03. Command 136: Independent Motor Drive (inB = ~inA)
Effect: Causes the specified motor to immediately drive forward (inA bit = 0) or reverse (inA bit = 1) with the
desired PWM
Values sent: motor (1 bit), inA (1 bit), PWM (8 bits)
command byte = 136 | (motor bit << 2) | (inA bit << 1) | MSB of PWM
data byte = 7 lower bits of PWM byte
3.a.04. Command 232: Independent Motor Drive with Acceleration (inB = ~inA)
Effect: Causes the specified motor to transition from its current direction and PWM to the desired direction PWM
at a rate determined by its corresponding acceleration setting. If the desired motor direction (forward for inA = 0
and reverse for inA = 1) is the same as the current direction and the desired PWM is less than the current PWM,
the PWM will be set directly to the desired value during the next PWM-update phase of the mega168 main loop
(sometime in the next 10ms). In short, this command will not produce artifical deceleration to slow a motor. The
only time the acceleration comes into play is when the PWM is increasing in a specific direction. If this command
results in a change of direction, the motor is first stopped by braking low at 100% duty cycle for a duration that
can be set using command 188 (Section 3.a.08). The PWM is then linearly incremented from zero to the desired
PWM in the desired direction based on the acceleration setting, which can be set using command 208 (Section
3.a.07). Acceleration updates to the PWM are performed 100 times per second if possible. It is important to note
that acceleration timing is done using the motor 1 PWM timer, so decreasing motor 1’s PWM frequency below
100Hz will decrease the acceleration update rate.
Values sent: motor (1 bit), inA (1 bit), PWM (8 bits)
command byte = 232 | (motor bit << 2) | (inA bit << 1) | MSB of PWM
Effect: Use dual motor drivers together as a single, more powerful motor driver. The settings of in1 and in2
determine if the effect is brake low, forward, or reverse at thedesired PWM. This command sets motor to the
specified state immediately. It is not possible to brake high in joint motor mode. It is also not possible to take
advantage of current-sensing while in joint motor mode. Joint motor control works by PWMing the low output
side while holding the other side constantly high. Here is how it performs the following actions:
• Joint brake (in1 = in2): both H-bridges alternate between high impedance and driving low at the same
synchronized duty cycle.
• Joint “forward” (in1 = 0, in2 = 1): H-bridge 1 alternates between high impedance and driving low while
H-bridge 2 drives high.
• Joint “reverse” (in1 = 1, in2 = 0): H-bridge 2 alternates between high impedance and driving low while
H-bridge 1 drives high.
The red/green LEDs on the daughter motor-driver board will not function in joint motor mode, nor will currentsensing. To run your X2 in joint motor mode, you should connect one side of your motor to the two M1 outputs
and the other side of your motor to the two M2 outputs.
command byte = 144 | (in1 bit << 2) | (in2 bit << 1) | MSB of PWM
data byte = 7 lower bits of PWM byte
3.a.06. Command 228: Joint Motor Drive with Acceleration (in2 = ~in1)
Effect: See “Independent Motor Drive with Acceleration” (Section 3.a.04) command. Joint Motor Drive uses the
dual motor drivers together as a single, more powerful motor driver. When operating in joint motor mode, settings
for operation are determined by “motor 1” (motor bit = 0) settings while “motor 2” settings are ignored.
Values sent: in1 (1 bit), PWM (8 bits)
command byte = 228 + (in1 bit << 1) + MSB of PWM
data byte = 7 lower bits of PWM byte
3.a.07. Command 208: Set Acceleration
Effect: Sets for the specified motor the acceleration used by the motor acceleration commands 228 (Section
3.a.06) and 232 (Section 3.a.04). While accelerating, the net effect is that the PWM is incremented by the
acceleration value every 100 ms. In reality, the updates will usually be increments of the one tenth the acceleration
value applied every 10 ms. The acceleration value for each motor is specified by a seven-bit number and will
change the duty cycle twice as quickly in seven-bit PWM mode as in eight-bit PWM mode. An acceleration value
of zero is treated as infinite acceleration and will simply set the PWM equal to the target PWM when the motorhandling portion of the mega168’s main loop is executed sometime in the next 10ms.
This command does not save the acceleration values to EEPROM, however they can be saved by issuing separate
EEPROM-write commands (240—Section 3.d.02) that store the values at the appropriate addresses (9 for motor
1, 10 for motor 2). It is possible to safely store 8-bit values at these location if you need even higher accelerations
than 127.
Values sent: motor acceleration (7 bits), motor (1 bit)
Effect: Sets the duration the specified motor spends braking low at 100% duty cycle when issued an acceleration
command (228—Section 3.a.06 or 232—Section 3.a.04) that results in a change of direction. The brake duration
value is in tens of milliseconds, so a value of 1 will result in a brake duration of 10 ms and a value of 127 will
result in a brake duration of 1.27 seconds. A brake duration value of 0 causes the motor to switch direction with
no braking in between. Brake duration is a seven-bit value.
This command does not save the brake duration value to EEPROM, however it can be saved by issuing a separate
EEPROM-write command (240—Section 3.d.02) that stores the value at the appropriate address (11 for motor 1,
12 for motor 2). It is possible to safely store 8-bit values at these location if you need longer brake durations than
1.27 seconds.
Note: this command is bugged in firmware version 1.00 and has no effect, but it has been fixed in version 1.01.
Values sent: motor (1 bit), brake duration (7 bits)
command byte = 188 | (motor bit << 1)
data byte = 7-bit brake duration (MSB always zero)
3.a.09. Command 212: Set Number of Current Sense Samples in Averages
Effect: This setting determines how many current sense samples will be in each motor’s current average. These
averages are what the Get Currents command (216—Section 3.a.12)) returns. Each motor’s current average is a
running average that is updated every other ADC conversion. The ADC can perform conversions at approximately
10 kHz, which means each motor’s current average is updated at approximately 5 kHz. The previous X samples
are stored in memory, and the average returned is the average of those X most recent samples. This setting
determines the value of X. The values are sent as three-bit, base-two exponents, meaning that the largest sample
size allowed per average is 27(128) while the smallest is 20(1).
It is important to note that current sensing is not possible in joint motor mode. As such, this command has no effect
when running in joint motor mode. It is also important to note that current sensing is only possible when using a
motor driver daughter board that has VNH2SP30s (the VNH3SP30 does not provide current sense feedback).
This command does not save this setting to EEPROM, however it can be saved by issuing separate EEPROMwrite commands (240—Section 3.d.02) that store the values at the appropriate addresses (3 for motor 1, 4 for
motor 2). The values stored in EEPROM should be the actual number of samples to average, not the exponents.
For example, if you are sending an exponent of 5 for motor 1 to the mega168 via this command, you should send
a value of 25(32) to be stored in byte 3 of the mega168’s EEPROM. The value you store must be a power of two.
Values sent: motor 1 current sense samples exponent (3 bits), motor 2 current sense samples exponent (3 bits)
command byte = 212
data byte = (motor 2 current sense samples exponent << 3) | motor 1 current sense samples exponent
3. Low-Level SPI CommandsPage 9 of 27
Loading...
+ 18 hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.