Grove I2C Motor Driver v1.3 - Frequency Change Not Working

Hello.
I am trying to create a PC fan controller for which the optimal frequency is ~25 kHz. I have a Seeeduino Lotus v1.0 plugged into I2C motor driver v1.3b. I am able to change my fan speed easily, but my frequency is way too low. With an oscilloscope I measure my frequency at only 30.12 Hz. I have tried changing PWMFrequencySet from 0x84 to 0x01 and 0xFF. I’ve also tried changing “Frequence” from 0x00 to 0xFF. I am seeing no change in frequency at all. Am I calling the function incorrectly? Please help.

This is my code:

[code]#include <Wire.h>

#define MotorSpeedSet 0x82
#define PWMFrequenceSet 0x01 //default 0x84
#define DirectionSet 0xaa
#define MotorSetA 0xa1
#define MotorSetB 0xa5
#define Nothing 0x01
#define EnableStepper 0x1a
#define UnenableStepper 0x1b
#define Stepernu 0x1c
#define I2CMotorDriverAdd 0x0f // Set the address of the I2CMotorDriver

void setup() {
Wire.begin(); // join i2c bus (address optional for master)
delayMicroseconds(10000);
Serial.begin(9600);
Serial.println(“setup begin”);
}

void loop() {
// the following code sent commands to motor driver to drive DC motor
while(1) {
Serial.println(“sent DC speed 100”);

delay(50);
MotorSpeedSetAB(50,100);//defines the speed of motor 1 and motor 2;
delay(50); //this delay needed
MotorDirectionSet(0b1010);  //"0b1010" defines the output polarity, "10" means the M+ is "positive" while the M- is "negtive"
                            // make sure M+ and M- is different polatity when driving DC motors.
delay(50);
MotorPWMFrequenceSet(0x01);
delay(5000);  
//MotorDirectionSet(0b0101);  //0b0101  Rotating in the opposite direction
delay(5000); 

}
}

//////////////////////////////////////////////////////////////////////
//Function to set the 2 DC motor speed
//motorSpeedA : the DC motor A speed; should be 0~100;
//motorSpeedB: the DC motor B speed; should be 0~100;

void MotorSpeedSetAB(unsigned char MotorSpeedA , unsigned char MotorSpeedB) {
MotorSpeedA=map(MotorSpeedA,0,100,0,255);
MotorSpeedB=map(MotorSpeedB,0,100,0,255);
Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
Wire.write(MotorSpeedSet); // set pwm header
Wire.write(MotorSpeedA); // send pwma
Wire.write(MotorSpeedB); // send pwmb
Wire.endTransmission(); // stop transmitting
}

//set the direction of DC motor.
void MotorDirectionSet(unsigned char Direction) { // Adjust the direction of the motors 0b0000 I4 I3 I2 I1
Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
Wire.write(DirectionSet); // Direction control header
Wire.write(Direction); // send direction control information
Wire.write(Nothing); // need to send this byte as the third byte(no meaning)
Wire.endTransmission(); // stop transmitting
}

//set the prescale frequency of PWM, 0x03 default;
void MotorPWMFrequenceSet(unsigned char Frequence) {
Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
Wire.write(PWMFrequenceSet); // set frequence header
Wire.write(Frequence); // send frequence
Wire.write(Nothing); // need to send this byte as the third byte(no meaning)
Wire.endTransmission(); // stop transmitting
}[/code]

I have made some progress. Using the default 0x84 for PWMFrequenceSet I can get different frequencies, but only a few useful ones:
PWMFrequenceSet MotorPWMFrequenceSet Frequency
0x84 0x00 30.12 Hz
0x84 0x01 1.923 kHz
0x84 0x02 250 Hz
0x84 0x03 30.12 Hz
0x84 0x04 7.5 Hz

What is the absolute maximum frequency the the PWM Motor Driver supports? I need 25 ~KHz. The 1.923 KHz makes too much noise.

I now realize my mistakes and confusion from my first post. “PWMFrequenceSet” is a constant which cannot be changed. It simply represents the command that is sent to the ATmega8A to change the frequency scaler. The ATmega8A uses this scaler to calculate the output frequency of the PWM pins. After looking extensively at the source code for the ATmega8A controller and datasheet for the ATmega8A, I am more clear on several things.

Only 0x01 - 0x05 are valid prescale values. They represent IOclk/0, IOclk/8, IOclk/64, IOclk/256, and IOclk/1024. Since I am getting only 2kHz with a prescaler of 0x01 (IOclk/0), then logically the IOclk should be 2kHz. But I am confused because I believe the ATmega8A is running at 1 MHz with the internal clock? Why is the IOclk 500 times slower? Where is this defined or how is it calculated? I cannot find this in the datasheet.

It has also become clear to me that the PCB board support adding an external oscillator. This would enable me to increase the clock to 8 or 16 Mhz. I have an Atmel AVR programmer on the way, so I can change the fuse bits and adjust clock settings.

If I can’t get help here, I’ll consider going to the AVR-Freaks forum, but I figured the manufacturer was the best resource first.

Hi, I just notice your topic, maybe I can share you some of my idea. :smiley:

If you solder a 16Mhz crystal, It would be better. I want to say that if you had an atmel programmer, why not try writing an Arduino style new firmware, the old one is wrote by AVR Studio, which is not such common.

If you want to write a new firmware, please let me know, I can be helped.
Or you can send me a email: [email protected].

I ordered and got my Atmel AVRISP MKII programmer yesterday. I am having trouble connecting to the Atmel ATmega8A. I just get an orange blinking light one he programmer. Is there something I need to know? Am I doing something wrong? I confirmed the programmer works with the Arduino Lotus and Arduino Uno. Is the ATmega8A on the motor controller locked or something? Any help is much appreciated.

Well, I figured it out on my own. It turns out, the capacitor to ground, C10 (100nF), is problematic with some programmers, and not necessary in the circuit. See this post:
http://electronics.stackexchange.com/questions/41495/what-values-of-resistor-and-capacitor-to-use-for-avr-reset-pin-isolation
I removed C10 (100nF) and plugged my Atmel AVRISP MKII programmer in and the status LED on the programmer instantly turned green. I am now able to connect to the ATmega8A on the Grove PWM Motor Driver board.

Next to come…

Changing fuse bits to change frequency and possibly use an external oscillator (16Mhz).

Thanks for your sharing, it’s useful to others while uploading a new firmware to I2C motor shield or other microcontroller, we will add it to our wiki, please tell me if you finish it.

Jacket

I have successfully changed the fuse bits and increased the frequency of the onboard micro to 8 MHz. I took screenshots and will try to post this weekend.

Also, I’ve ordered the 16 MHz crystal and capacitors needed to add to the board which will let me double the frequency. I probably won’t be able to solder them on for two weeks as I leave for a business trip on Sunday.

First I will show the screen shot of the output when the ATmega8 is changed to operate at 8 MHz with the internal clock. This means no additional parts are necessary, just software change. The maximum frequency of the output at 8 MHz is ~16 KHz. Here are the results with different pre-scalers:

0x04 pre-scaler with CPU @ 8 MHz & 50% Duty Cycle:

0x03 pre-scaler with CPU @ 8 MHz & 50% Duty Cycle:

0x02 pre-scaler with CPU @ 8 MHz & 50% Duty Cycle:

0x01 pre-scaler with CPU @ 8 MHz & 50% Duty Cycle:

So the results are:
0x04 -> ~62.5 Hz
0x03 -> ~250 Hz
0x02 -> ~2.0 KHz
0x01 -> ~16 KHz

Please correct me if any of my measurements appear incorrect! I want this to be as accurate as possible.

To get to 32KHz output, it is necessary to increase the clock of the ATmega8 to 16MHz. For this we need to add an external crystal. The board already has unpopulated pads for this, so all we need are the parts. The parts I used are:

Digikey:
Crystal 16MHZ 8pF SMD - 644-1188-1-ND
Ceramic Capacitor 22pF 50V 10% 0805 - 399-8036-1-ND
Ceramic Capacitor 12pF 50V 5% 0805 - 399-1110-1-ND

You will also need a 2x3 header for the ISP connector. I ended up using the 12pF capacitors for both locations. There are a range of capacitors that can be used for this application (if you have a more intimate knowledge of how to select the correct capacitor, please let me know). I have some parts left over, so if you live in the USA, PM me and I can post them to you for the cost of a stamp.

After soldering these components on, I learned that I probably should have ordered 0603 sized capacitors. Instead, use this capacitor:
Ceramic Capacitor 12pF 50V 5% 0603 - 399-1050-1-ND

Seeed employee:
Please provide the part numbers that you recommend from your website and I will add them to the list as alternatives.

Images of before:

I added the crystal to X1, and capacitors to C9 and C6. Also, note the addition of the ISP header. Image of after:

Next up: Configuring Fuse bits in Atmel Studio!

For this step you will need an AVR ISP programmer. You can get one from Seeed here:
http://www.seeedstudio.com/depot/Atmel-AVRISP-STK500-USB-ISP-Programmer-p-207.html

I got mine from FeaBay at quite a good price.

Once you have the AVR programmer, install the latest version of Atmel Studio on your computer:
http://www.atmel.com/tools/atmelstudio.aspx

Also, refrence my previous post regarding the removal of C10 from the circuit board if you have issues communicating with the ATmega8 microcontroller on the Grove Motor board.

In Atmel Studio go to the “Tools” menu and then “Device Programming”. The “Device Programming” window should open and change the “Tool” to AVRISP mkII if that is what you are using. Also select “ATmega8A” as the “Device” and “ISP” as the “Interface”.

The original settings of the fuses should look like this:

To change the internal clock to 8Mhz you need to change “SUT_CKSEL” under “Fuses” to “INTRCOSC_8MHZ_6CK_64MS”:

Then click “Program”:

If you want to use an external 16Mhz crystal, you need to change “SUT_CKSEL” to “EXTHIFXTALRES_16KCK_64MS”: