PDA

View Full Version : Arbotix, Arduino, and Timers



draikani
04-05-2012, 08:40 PM
So I recently got an Arbotix to replace my MiniRobocontroller as I was out of pins and needed the extra serial port. Now my code worked on the MiniRobocontroller. The Motors library was using Timer0, the Hservo library was using Timer1, an I had the following code using Timer2 to generate 1ms interrupts.


// First disable the timer overflow interrupt while we're configuring
TIMSK2 &= ~(1<<TOIE2);
// Configure timer2 in normal mode (pure counting, no PWM etc.)
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
// Select clock source: internal I/O clock
ASSR &= ~(1<<AS2);
// Disable Compare Match A interrupt enable (only want overflow)
TIMSK2 &= ~(1<<OCIE2A);
// Now configure the prescaler to CPU clock divided by 128
TCCR2B |= (1<<CS22) | (1<<CS20); // Set bits
TCCR2B &= ~(1<<CS21); // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 125000 Hz = 8us.
* (desired period) / 8us = 125.
* MAX(uint8) + 1 - 125 = 131;
*/
// Save value globally for later reload in ISR
tcnt2 = 131;
// Finally load end enable the timer
TCNT2 = tcnt2;
TIMSK2 |= (1<<TOIE2);

and my ISR:


ISR(TIMER2_OVF_vect)
{
// Reload the timer
TCNT2 = tcnt2;
// increment the system_timer
system_time = system_time++;
}



My code doesn't make use of arduino's mills(), micro(), or delay() functions, but am I correct in thinking that using all three timers would have broken these?

So the Arbotix uses Timer2 for its motor driver library, which means I needed to switch my 1ms interrupt over to Timer0. I modified my code to look like this:


// First disable the timer overflow interrupt while we're configuring
TIMSK0 &= ~(1<<TOIE0);
// Configure timer2 in normal mode (pure counting, no PWM etc.)
TCCR0A &= ~((1<<WGM01) | (1<<WGM00));
TCCR0B &= ~(1<<WGM02);
// Select clock source: internal I/O clock
ASSR &= ~(1<<AS2);
// Disable Compare Match A interrupt enable (only want overflow)
TIMSK2 &= ~(1<<OCIE2A);
// Now configure the prescaler to CPU clock divided by 128
TCCR0B |= (1<<CS22) | (1<<CS20); // Set bits
TCCR0B &= ~(1<<CS21); // Clear bit
/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 125000 Hz = 8us.
* (desired period) / 8us = 125.
* MAX(uint8) + 1 - 125 = 131;
*/
// Save value globally for later reload in ISR
tcnt0 = 131;
// Finally load end enable the timer
TCNT0 = tcnt0;
TIMSK0 |= (1<<TOIE0);


With this ISR:


ISR(TIMER0_OVF_vect)
{
// Reload the timer
TCNT0 = tcnt0;
// increment the system_timer
system_time = system_time++;
}


When I try to compile I get this error:

core.a(wiring.c.o): In function `__vector_18':
/Users/jeffreydamelio/Documents/Arduino/hardware/arbotix/cores/arbotix/wiring.c:45: multiple definition of `__vector_18'
Sparky_1_0_arduino22.cpp.o:Sparky_1_0_arduino22.cp p:207: first defined here


As near as I can tell, the file that modifies Millis(), micro(), etc. for use on the 644p is already trying to use this interrupt vector. Is this correct? What do I change to make this work? And thanks in advance to all the helpful people.

lnxfergy
04-05-2012, 09:17 PM
Timer0 is used by Arduino to generate their system clock, so wiring.c includes a Timer0 overflow interrupt already. This is one of the reasons the ArbotiX switched to using Timer2 for motors, we can change the timer clock frequency to get higher-frequency PWM without screwing up the system clock.

To make your code work, you'll either have to disable the Arduino system clock (besides breaking millis(), etc, not sure what implications this has), or do some sort of trickery with Timer2 to support both the motor PWM and your clock.

Out of curiosity, why did you need your own system clock?

-Fergs

draikani
04-05-2012, 09:24 PM
I just had systemtime in my ISR incrementing every 1ms for use in timing things in my various tasks, as I have multiple things going on that need to be timed but are really not at all picky about accuracy. I wasn't aware that Arduino already had something similar going on, and while I don't need their mills() etc. I don't really feel like risking messing up other things. Can I accomplish this same sort of timing using Arduino's system clock?

draikani
04-05-2012, 09:37 PM
Actually this is exactly what mills() is for isn't it... derp. :confused:

I feel like there was some reason I didn't do this initially, but I don't remember it now. Oh well.

draikani
04-06-2012, 02:51 AM
Ok, heres another thing I can't find the answer for. The pinout on the Arbotix is confusing me. If for example I wanted to do an analog read on A7, analogRead(7); works, but I'm having trouble seeing the pattern. If all I give it is 7, how does it know I'm talking about the analog pin 7 and not the digital pin 7? What if I want to do a digitalRead on A7? None of the wiring diagrams seem to quite match what is actually working for me.

lnxfergy
04-06-2012, 03:06 AM
Ok, heres another thing I can't find the answer for. The pinout on the Arbotix is confusing me. If for example I wanted to do an analog read on A7, analogRead(7); works, but I'm having trouble seeing the pattern. If all I give it is 7, how does it know I'm talking about the analog pin 7 and not the digital pin 7? What if I want to do a digitalRead on A7? None of the wiring diagrams seem to quite match what is actually working for me.

The analogRead function only knows about analog pins, which are number 0-7.

The trick to using digitalRead() is that DIGITAL = 31 - ANALOG for the analog pins, that is, analog 0 is digital 31. This is a left over annoyance from the Sanguino standard. Arduino recently introduced the notion of using "digitalRead(A7)" where A7 would be defined to be the correct digital pin, however, this is not yet in a release of ArbotiX (it is available in trunk of SVN, and will be available in our next release).

-Fergs

draikani
04-06-2012, 02:12 PM
Thanks for the quick replies Fergs, really makes the Arbotix a pleasure to use. So one more question, what do I need to do to use the second serial port as a regular serial port? I'm trying to use it with spark fun's serial lcd backpack. I tried Serial1.begin(9600); and got:

Sparky_1_0_arduino22:759: error: 'Serial1' was not declared in this scope

This is because the Arbotix sets it aside for Bioloid things right?

draikani
04-07-2012, 08:44 PM
Ok so I modified the hardwareserial.h and hardwareserial.cpp files by uncommenting the lines related to Serial1, and adding a line defining rx_buffer1. Now it sort of works, but it's being very finicky. I have to power up the Arbotix with the FTDI chip disconnected, then plug it in, then reset the arbotix. Even if I don't intend to use the FTDI chip I still have to power on and then reset. Am I at least on the right track here?

draikani
04-07-2012, 08:49 PM
oops double