X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=main.c;h=82739b098a90a178ea284306fad53e127a9589e8;hb=31b666597c0014c64be6230df6451ec062524522;hp=53fd747dc8b45f40a82bc523c3e4045ec2901f97;hpb=e3f43b953a1103fa4e9f4f932a04e8ab51b3b884;p=protos%2Frc_servos.git diff --git a/main.c b/main.c index 53fd747..82739b0 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,5 @@ #include +#include struct servo { uint8_t bit; @@ -7,34 +8,173 @@ struct servo { static struct servo servo_table[] = { { - .bit = 0, - .command = 0, + .bit = 2, + .command = 300, + }, + { + .bit = 3, + .command = 700, }, { - .bit = 1, + .bit = 4, .command = 512, }, { - .bit = 2, - .command = 1023, + .bit = 5, + .command = 512, + }, + { + .bit = 6, + .command = 512, + }, + { + .bit = 7, + .command = 512, }, }; +#define NB_SERVO (sizeof(servo_table)/sizeof(*servo_table)) + +static uint8_t bypass; +static volatile uint8_t done; +static uint8_t portval; +static uint8_t rxidx; + +static uint8_t icp_idx = NB_SERVO; +static uint16_t icp_servos[NB_SERVO]; +static uint16_t icp_prev; + +#define BYPASS_ENABLE 14 +#define BYPASS_DISABLE 15 -static volatile uint8_t rxbuf[16]; -register uint8_t rxlen asm("r2"); -register uint8_t done asm("r3"); -register uint8_t portval asm("r4"); -register uint8_t bypass asm("r5"); +#define LED_ON() do { PORTB |= 0x02; } while(0) +#define LED_OFF() do { PORTB &= ~0x02; } while(0) + +/* + * SPI protocol: + * + * A command is stored on 2 bytes. The first one has its msb to 0, and the + * second one to 1. The first received byte contains the command number, and the + * msb of the servo value. The second byte contains the lsb of the servo value. + * + * Commands 0 to NB_SERVO are to set the value of servo. + * Command 14 is to enable bypass mode. + * Command 15 is to disable bypass mode. + */ +static union { + uint8_t u8; + struct { + /* inverted: little endian */ + uint8_t val_msb:3; + uint8_t cmd_num:4; + uint8_t zero:1; + }; +} byte0; + +static union { + uint8_t u8; + struct { + /* inverted: little endian */ + uint8_t val_lsb:7; + uint8_t one:1; + }; +} byte1; SIGNAL(TIMER1_COMPA_vect) { - PORTC = portval; + PORTD = portval; TIMSK1 &= ~_BV(OCIE1A); done = 1; } static void poll_spi(void) { + uint8_t c; + + /* reception complete ? */ + if (!(SPSR & (1< 2000) { + icp_idx = 0; + return; + } + + /* get the value for the servo */ + if (rising == 0 && icp_idx < NB_SERVO) { + if (diff < 1000) + icp_servos[icp_idx] = 0; + else + icp_servos[icp_idx] = diff - 1000; + icp_idx++; + } +} + +static void poll(void) +{ + poll_spi(); + poll_input_capture(); } static void load_timer_at(uint16_t t) @@ -52,40 +192,61 @@ static void do_one_servo(struct servo *s) //portval = PORTC | (1 << s->bit); portval = (1 << s->bit); t = TCNT1; - load_timer_at(t + 150); + load_timer_at(t + 20); while (done == 0) - poll_spi(); + poll(); /* reset bit */ done = 0; portval = 0; //portval = PORTC & (~(1 << s->bit)); - load_timer_at(t + 150 + 8000 + s->command * 8); + load_timer_at(t + 20 + 1000 + s->command); while (done == 0) - poll_spi(); + poll(); } int main(void) { uint8_t i; uint8_t t, diff; + uint8_t tmp; + + /* use pull-up for inputs */ + PORTC |= 0x3f; - DDRB = 0x20; - DDRC = 0x7; + /* LED */ + DDRB = 0x02; - /* start timer1 at clk/1 (8Mhz) */ +#if 0 /* LED debug */ + while (1) { + LED_ON(); + wait_ms(100); + LED_OFF(); + wait_ms(100); + } +#endif + + /* servo outputs PD2-PD7 */ + DDRD = 0xfc; + + /* start timer1 at clk/8 (1Mhz), enable noise canceler on + * input capture, capture rising edge */ TCNT1 = 0; - TCCR1B = _BV(CS10); + TCCR1B = _BV(CS11) | _BV(ICNC1) | _BV(ICES1); /* start timer0 at clk/1024 (~8Khz) */ TCNT0 = 0; TCCR0B = _BV(CS02) | _BV(CS00); + /* enable spi (don't set unused MISO as output) */ + SPCR = _BV(SPE); + sei(); + bypass = 0; while (1) { t = TCNT0; - for (i = 0; i < sizeof(servo_table)/sizeof(*servo_table); i++) { + for (i = 0; i < NB_SERVO; i++) { do_one_servo(&servo_table[i]); } /* wait 20 ms */ @@ -93,11 +254,20 @@ int main(void) diff = TCNT0 - t; if (diff >= 160) break; - poll_spi(); + poll(); } /* bypass mode */ - while (bypass == 1) { - PORTC = PORTB; + if (bypass == 1) { + LED_ON(); + + while (bypass == 1) { + tmp = PINC; + tmp &= 0x3f; + tmp <<= 2; + PORTD = tmp; + poll(); + } + LED_OFF(); } }