summaryrefslogtreecommitdiff
path: root/peripheral/libupm/src/grovemd/grovemd.h
blob: 948347520c5e8457664e8130c9c3533e0cc69d2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#pragma once

#include <stdint.h>
#include <sys/time.h>
#include <string>
#include <mraa/types.hpp>
#include <mraa/i2c.hpp>

#define GROVEMD_I2C_BUS 0
#define GROVEMD_DEFAULT_I2C_ADDR 0x0f

namespace upm {
  /**
   * @brief Grove I2C Motor Driver library
   * @defgroup grovemd libupm-grovemd
   * @ingroup seeed i2c motor robok
   */

  /**
   * @library grovemd
   * @sensor grovemd
   * @comname Grove I2C Motor Driver
   * @type motor
   * @man seeed
   * @con i2c
   * @kit robok
   *
   * @brief API for the Grove I2C Motor Driver 
   *
   * This class implements support for the Grove I2C Motor Driver.
   * This device can support a single 4-wire stepper motor, or two
   * 2-wire DC motors. The device contains an Atmel* ATmega8L
   * microcontroller that manages an L298N H-bridge driver chip.
   *
   * This device supports an I2C bus speed of 100Khz only.
   *
   * The module does not provide any telemetry or status - it only
   * accepts I2C commands for its various operations.
   *
   * This module was tested with version 1.3 of the Grove I2C Motor
   * Driver.
   *
   * For stepper operation, this driver can run in one of two modes -
   * Mode 1, where this driver handles the stepping operation, and
   * Mode 2, where this driver simply sends commands to the Grove
   * Motor Driver, and it handles the stepping operation.  Mode2
   * requires updated (and working) firmware to be loaded onto the
   * device.
   *
   * The default stepper operation mode is Mode1, which is generally
   * more flexible and is supported on all firmware revisions.
   *
   * @image html grovemd.jpg
   * An example showing the use of a DC motor
   * @snippet grovemd.cxx Interesting
   * An example showing the use of a 4-wire stepper
   * @snippet grovemd-stepper.cxx Interesting
   */
  class GroveMD {

  public:
    // GroveMD registers
    typedef enum { SET_SPEED           = 0x82,
                   SET_PWM_FREQ        = 0x84,
                   SET_DIRECTION       = 0xaa,
                   SET_MOTOR_A         = 0xa1, // not documented
                   SET_MOTOR_B         = 0xa5, // not documented
                   STEPPER_ENABLE      = 0x1a, 
                   STEPPER_DISABLE     = 0x1b,
                   STEPPER_NUM_STEPS   = 0x1c
    } REG_T;

    // legal directions for the stepper
    typedef enum { STEP_DIR_CCW    = 0x01,
                   STEP_DIR_CW     = 0x00
    } STEP_DIRECTION_T;
    
    // legal directions for individual DC motors
    typedef enum { DIR_CCW    = 0x02,
                   DIR_CW     = 0x01
    } DC_DIRECTION_T;
    
    // stepper modes
    typedef enum { STEP_MODE1 = 0x00,
                   STEP_MODE2 = 0x01
    } STEP_MODE_T;
    
    /**
     * GroveMD constructor
     *
     * @param bus I2C bus to use
     * @param address I2C address to use
     */
    GroveMD(int bus=GROVEMD_I2C_BUS, 
            uint8_t address=GROVEMD_DEFAULT_I2C_ADDR);

    /**
     * GroveMD destructor
     */
    ~GroveMD();

    /**
     * Composes and writes a 3-byte packet to the controller
     *
     * @param reg Register location
     * @param data1 First byte of data
     * @param data2 Second byte of data
     * @return True if successful
     */
    bool writePacket(REG_T reg, uint8_t data1, uint8_t data2);

    /**
     * To control DC motors, sets the speed of motors A & B.
     * Valid values are 0-255.
     *
     * @param speedA Speed of motor A
     * @param speedB Speed of motor B
     * @return True if successful
     */
    bool setMotorSpeeds(uint8_t speedA, uint8_t speedB);

    /**
     * To control DC motors, sets the PWM frequency prescale
     * factor. Note: this register is not ducumented other than to say
     * the default value is 0x03. Presumably, this is the timer
     * prescale factor used on the ATMega MCU timer driving the PWM.
     *
     * @param freq PWM prescale frequency; default is 0x03
     * @return True if successful
     */
    bool setPWMFrequencyPrescale(uint8_t freq=0x03);

    /**
     * To control DC motors, sets the directions of motors A & B
     *
     * @param dirA Direction for motor A, DIR_CW or DIR_CCW
     * @param dirB Direction for motor B, DIR_CW or DIR_CCW
     * @return True if successful
     */
    bool setMotorDirections(DC_DIRECTION_T dirA, DC_DIRECTION_T dirB);

    /**
     * To control a stepper motor, sets its direction and speed, and
     * then starts operation.  For Mode2, this method will return
     * immediately.  For Mode1 (the default) this method returns when
     * the number of steps specified by setStepperSteps() has
     * completed.
     *
     * @param dir Direction, STEP_DIR_CW or STEP_DIR_CCW
     * @param speed Motor speed. Valid range is 1-255. For Mode 1
     * (default), this specifies the speed in RPM's.  For Mode 2,
     * speed is multiplied by 4ms by the board, so higher numbers
     * will mean a slower speed.
     * @return True if successful
     */
    bool enableStepper(STEP_DIRECTION_T dir, uint8_t speed);

    /**
     * To control a stepper motor, stops the stepper motor.
     *
     * @return True if successful
     */
    bool disableStepper();

    /**
     * To control a stepper motor, specifies the number of steps to
     * execute. For Mode2, valid values are between 1-255, 255 means
     * continuous rotation.
     *
     * For Mode1 (the default) steps can be any positive integer.
     *
     * @param steps Number of steps to execute. 255 (only in Mode2)
     * means continuous rotation.  
     * @return True if successful
     */
    bool setStepperSteps(unsigned int steps);

    /**
     * Configure the initial Stepper parameters.  This should be
     * called before any other stepper method.
     *
     * @param stepsPerRev The number of steps required to complete one
     * full revolution.
     * @param mode The stepper operating mode, default STEP_MODE1
     * @return Elapsed milliseconds
     */
    void configStepper(unsigned int stepsPerRev, STEP_MODE_T mode=STEP_MODE1);

  protected:
    mraa::I2c m_i2c;
    uint8_t m_addr;

  private:
    // steps per revolution
    int m_stepsPerRev;
    int m_currentStep;
    uint32_t m_stepDelay;
    uint32_t m_totalSteps;
    STEP_MODE_T m_stepMode;

    /**
     * Steps the motor one tick
     *
     */
    void stepperStep();

    // step direction: - 1 = forward, -1 = backward
    int m_stepDirection;

    // This is a NOOP value used to pad packets
    static const uint8_t GROVEMD_NOOP = 0x01;
    // our timer
    struct timeval m_startTime;

    /**
     * Returns the number of milliseconds elapsed since initClock()
     * was last called.
     *
     * @return Elapsed milliseconds
     */
    uint32_t getMillis();

    /**
     * Resets the clock
     *
     */
    void initClock();

  };
}