328P timing problem I2C Clock 200Khz?

Hello,

I have an Arduino Duemilanove (with ATMega328P), and I also have an I2C device to interface with, the MD25 motor controller from Devantech.

This interface was running fine until a couple of days ago when I belive I burnt out the data line (SDA) on my arduino 328 chip (dont know how). The clock line was still pumping out a solid 100Khz clock, verified with my oscilliscope. but nothing on the dataline, so I assumed the ATMega328 is not very well.

I ordered a new ATMega 328P-PU from the same supplier as the board with the bootloader preloaded as I do not have an ICSP programmer. Putting the exact same Arduino Sketch that was working perfectly with my old 328 give me an exact 200Khz clock on SCL!! Needless to say the I2C interface does not work.

The only other thread I could find about this was one regarding Serial data being sent twice as fast. (Which i tried to link but I need more messages).

My board has a 16MHz crystal, and it worked perfectly with my old chip, I thought that maybe my chip is an 8Mhz and this is getting its speed doubled? I ruled this out when I tried timing some pin HIGH/LOWs with delays of 500ms, it clocks correctly at 500ms on my oscilliscope.

I am left with the problem being timing and I2C related, the chips are exactly the same apart from a four digit number (0910 and 0927) are these the batch numbers?

I have been stuck with this for a couple of days so would really appreciate any ideas you guys could think of?

Many Thanks!

Print out the contents of register TWBR. It should be 72 for a 16 MHz board running a 100KHz I2C.

If it's not then you can set about finding out why not. That's the approach I took to track down the cause of the serial problem.

EmilyJane,

Thank you for your response. Unless I am doing something wrong my TWBR register is returning 0.

I assume this is all that is required?

byte theRegister = TWBR; Serial.println(a, HEX);

I have tried this on both chips, both return 0.

I try writing 72 to this register, however it has no effect. I really dont know what is going on here...

EDIT: digitalWrite(4, HIGH); delay(500); digitalWrite(4, LOW); delay(500); digitalWrite(4, HIGH); delay(500); digitalWrite(4, LOW); delay(500); digitalWrite(4, HIGH); delay(500); digitalWrite(4, LOW);

Above delays give me exactly 500ms delays between HIGH/LOW on my scope.

So...

According to the datasheet.

SCL Frequency = CPU Frequency / ( (16 + (2*TWBR)) * TWSR)

So... currently my TWSR is 0xF8, which is 11111000, or, a prescaler value of 1. My TWBR is giving me 0, and my chip SHOULD be 16mhz (at least the crystal is) so...

SCL Frequency = 16000000 / ( (16 + (2*0)) * 1 ) http://www05.wolframalpha.com/input/?i=(16Mhz+%2F+(+(16+%2B+(2*0))+*+1))+in+KHz SCL Frequency = 1000Khz, much too fast.

SCL Frequency = 16000000 / ( (16 + (2*72)) * 1 ) http://www05.wolframalpha.com/input/?i=(16Mhz+%2F+(+(16+%2B+(2*72))+*+1))+in+KHz SCL Frequency = 100Khz, perfect...

I have tried writing 72 to the TWBR but no joy, can you suggest how I can get this value to stick/take effect?

Edit: My first chip giving me 100Khz is right... but reading the TWBR of that is giving me 0. Which makes me think writing TWBR will do nothing. I cant seem to find the code for the TWI library? Would there be anything in their to help?

Thanks.

Bit of a wild goose chase that TWBR. I was stupidly checking it/writing it before i called Wire.begin();

Here is the call from twi_init which is called by Wire.begin() to set TWBR. TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2;

Checking TWBR after this occurs gives me the magic 72! Only this happens on both chips, the new one is still giving me the wrong clock of 200Khz. Argh :-?

Okay… Ignoring the fact that this is totally wrong, setting 152 as the TWBR value would give me a value of 50Khz. Infact after checking with a scope it gives me my desired frequency of 100Khz, so something is definatly wrong with I2C here.

I decided to push on as I’d got a 100Khz clock and try and push some data though… i think my data is very off. I dont know how long a pulse takes on the dataline, but most of them on my scope are 20us, I would assume they should be very close to 10us for the clock to work? (The clock being 10us??)

Anyone know better than I why i have to increase my TWBR to get 100Khz?

In order to get the right TWI baudrate, you will also need to configure the prescaler as follows.

  cbi(TWSR, TWPS0);
  cbi(TWSR, TWPS1);
  TWBR=72;

So to check the configuration, you need to print both the TWSR and TWBR registers.

TWSP0 is bit0 and TWSP1 is bit1 of TWSR. Both are 0 which selects "1" as prescaler.

The formula for determining TWI clock frequency is as follows:

SCL freq = CPU freq / (16 +2 * TWBR * Prescaler)

E.g. SCL = 16MHz / (16 + 2 * 72 * 1) = 100kHz

Suppose the prescaler is not set to 1 the next available option is 4, which to me doesn't explain OPs situation.

BenF,

Thank you, my prescaler is set to 1. Or (TWSR = 11111000).

Having set TWBR to 152 I now get a 100Khz pulse on the Clock Line.

My data appears to be correct, checking on my oscilliscope I see the data bits I expect (7 bit address, write bit, ACK bit).

The ACK bit is getting pulled down for my EEPROM but not for my motor controller... which makes me think I bust the motor controller at the same time as my original chip =(

Thanks for the help though. I will ring my supplier in the morning to see if they have any ideas. I really cant make head nor tale of the clock problem cause the data appears to be right!!

Suppose the prescaler is not set to 1 the next available option is 4, which to me doesn't explain OPs situation.

True.

I belive I burnt out the data line (SDA) on my arduino 328 chip (dont know how).

You may want to double/triple check your wiring - things to check include:

  • Use short wires for SCL/SDA (at least for testing)
  • Use external pullups (close to the 328) both for SCL and SDA (4.7k)
  • Remember common ground to anything you interface.
  • Are logic levels the same (3.3 vs. 5)
  • Is the CPU firmly seated in its socket (check for bent pins)
  • Check for solder droplets (e.g. socket, CPU pins, other)
  • Check for small wiring fragments left on the board (e.g. stuck in the socket).

BenF,

Thank you for your suggestions.

I am using very short wires to test this, I was using 1k resistors with it working fine, I switched to 4.7k resistors as you suggested with no effect. All my logic is running at 5v and all grounds have been checked.

I know (think) the first chips SDA is broken because it reads 0v at all time when it should be 5v whilst no data is being carried on it. (And you see no data whilst some is being sent in code).

Checking the SDA line of the second chip with the hacked TWRB to 152 shows clean data, the address the read/write flag, except the ACK is not pull down as it should be by the motor controller. Needless to say no data is returned.

All this worked a couple of days ago until nothing would work, I must have burned out my 328, which is why I bought the second 328 (which clocked at 200Khz), I can only assume I have done the same to the controller? :’(

Thanks.

Not understanding why things go wrong in the first place - sure is frustrating as you may have yet another faulty CPU or more (sorry to even suggest this).

One thing I noticed from the MD25 spec. is that it is designed to be powered from a battery (e.g. 12V led acid). Without a battery in the circuit, there is potential risk with inductive loads (e.g. motors) sourcing back power spikes onto your power rails when breaking. You may want to consider this if it is applicable for your test environment.

BenF,

Thank you, i'm not sure if the induction was an issue in the burning out of my lines. I am using a 12v power transformer in place of a battery whilst testing. I will in future use a diode from this to my motor controller. I am powering the arduino off the USB power, and the motor controller (with no motors at the moment) off the transformer, with joined grounds, this should help seperate the inductive load from the Arduino?

I am currently waiting on a reply from my chip supplier, I will either get them to replace the chip or fix the issue. If i get a chip which comes brand new and gives me my 100Khz clock and the MD25 is still not responding I can only assume I have blown that also.

Thank you for your help.

As long as a motor is not connected, inductive loads would not materialize and explain the issues with burmed out chips.

When you operate a motor (power the rotor windings) this will transform into torque and movement, but when you remove power the opposite is true. The motor inertia will keep the rotor turning for a short while and induct electricty (high current) that may appear on your power rails (depends on the motor controller design). When a battery is the power source, this is not so much an issue as it will act as a gigantic capacitor absorbing the reverse power (it may even be desired as the battery could recharge from this current). When powered by a switch mode power supply with shared logic ground however, the reverse power may cause harm to logic connected to the controller and also the controller itself.

The issue with inductive reverse loads is not something a motor controller designer would forget or ignore as it is fundamental to deal with this properly. If a controller is designed specifically for battery power however it may not work well with switch mode power supplies. Yoy may want to seek advice from the motor controller supplier/manufacturer if you plan to operate the final design from a switch mode supply rather than a battery. Asking the supplier is good as that they can be made accountable for their advice.

I hope you find the cause of your issues and share your gained wisdom with the forum.

Hi !

You seem to be able to operate the MD25 with Arduino ! This is what i am still struggling with...

Can you help me with an example sketch ?

I was only able to find one for the MD23, but it's not compatible with the MD25 !

Thank you !

sondies,

Sorry for the super late reply, I found out that my MD25 was broken so I sent it back and got a replacement.

I used the MD23 code that someone had posted online, you probably have the same code.

I think I did have to change this code to get the encoders to read right.

long MD23::getEncoder1()
{
      // read a 32bit long value containing the encoder reading.
      // the reading of the highest byte capture the value.
      long first = readRegisterByte(ENC_1_A_REGISTER);
      
      return (first << 24) ^
         (((long)readRegisterByte(ENC_1_A_REGISTER+1)) << 16) ^
         (((long)readRegisterByte(ENC_1_A_REGISTER+2)) << 8) ^
         (((long)readRegisterByte(ENC_1_A_REGISTER+3)) );
}

long MD23::getEncoder2()
{
      // read a 32bit long value containing the encoder reading.
      // the reading of the highest byte capture the value.
      long first = readRegisterByte(ENC_2_A_REGISTER);
      
      return (first << 24) ^
         (((long)readRegisterByte(ENC_2_A_REGISTER+1)) << 16) ^
         (((long)readRegisterByte(ENC_2_A_REGISTER+2)) << 8) ^
         (((long)readRegisterByte(ENC_2_A_REGISTER+3)) );
}

Now however I’ve got the same problem, so I think my MD25 is broken again… Its not a very reliable board!! I’m looking for another board to drive the motors, as they seem reliable. Basically all you need is a H-Bridge and some way of reading the encoders. Basically quadrature with A+B pulses… I’m still looking into this…

Can anyone recommend a good motor/driver combo that doesnt break so easily?? But has encoders built in.