Help with Servos and SPI for RGB matrix

Hello everyone.

I’m making a small animatronic that uses servos for head movement and an ORM2088RGB-5 RGB 8x8 Matrix. The components work well separately but when I try to program both together, the servos stop moving.

The servos work using the Servo library to get to the desired positions (using the sweep example code).

The code for the matrix works using SPI communication with shift register so that only 3 pins (MOSI, Clock, Latch) are used to control the whole array.

The code is too big, so I’m attaching it to this post.

The lines which seem to be the cause of the problem are the following:

setup_hardware_spi();
...
...
setup_timer1_ovf();
...
...
void setup_hardware_spi(void) {
  byte clr;
  // spi prescaler: 
  // SPI2X SPR1 SPR0
  //   0     0     0    fosc/4
  //   0     0     1    fosc/16
  //   0     1     0    fosc/64
  //   0     1     1    fosc/128
  //   1     0     0    fosc/2
  //   1     0     1    fosc/8
  //   1     1     0    fosc/32
  //   1     1     1    fosc/64
  SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
  //SPCR |= ( (1<<SPR1) ); // set prescaler bits
  SPCR &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
  clr=SPSR; // clear SPI status reg
  clr=SPDR; // clear SPI data reg
  SPSR |= (1<<SPI2X); // set prescaler bits
  //SPSR &= ~(1<<SPI2X); // clear prescaler bits
}

void setup_timer1_ovf(void) {
  // Arduino runs at 16 Mhz...
  // Timer1 (16bit) Settings:
  // prescaler (frequency divider) values:   CS12    CS11   CS10
  //                                           0       0      0    stopped
  //                                           0       0      1      /1  
  //                                           0       1      0      /8  
  //                                           0       1      1      /64
  //                                           1       0      0      /256 
  //                                           1       0      1      /1024
  //                                           1       1      0      external clock on T1 pin, falling edge
  //                                           1       1      1      external clock on T1 pin, rising edge
  //
  TCCR1B &= ~ ( (1<<CS11) );
  TCCR1B |= ( (1<<CS12) | (1<<CS10) );      
  //normal mode
  TCCR1B &= ~ ( (1<<WGM13) | (1<<WGM12) );
  TCCR1A &= ~ ( (1<<WGM11) | (1<<WGM10) );
  //Timer1 Overflow Interrupt Enable  
  TIMSK1 |= (1<<TOIE1);
  TCNT1 = __TIMER1_MAX - __TIMER1_CNT;
  // enable all interrupts
  sei(); 
}


ISR(TIMER1_OVF_vect) { /* Framebuffer interrupt routine */
  TCNT1 = __TIMER1_MAX - __TIMER1_CNT;
  byte cycle;
  
  digitalWrite(__display_enable,LOW); // enable display inside ISR
  
  for(cycle = 0; cycle < __max_brightness; cycle++) {
    byte led;
    byte row = B00000000; // row: current source. on when (1)
    byte red;     // current sinker, on when (0)
    byte green;     // current sinker, on when (0)
    byte blue;      // current sinker, on when (0)

    for(row = 0; row <= __max_row; row++) {
      
      red = B11111111;    // off
      green = B11111111;  // off
      blue = B11111111;   // off
      
      for(led = 0; led <= __max_led; led++) {
        if(cycle < brightness_red[row][led]) {
          red &= ~(1<<led);
        }
        //else {
        //  red |= (1<<led);
        //}
          
        if(cycle < brightness_green[row][led]) {
          green &= ~(1<<led);
        }
        //else {
        //  green |= (1<<led);
        //}
        if(cycle < brightness_blue[row][led]) {
          blue &= ~(1<<led);
        }
        //else { 
        //  blue |= (1<<led);
        //}
      }

      digitalWrite(__spi_latch,LOW);
      spi_transfer(B00000001<<row);
      spi_transfer(blue);
      spi_transfer(green);
      spi_transfer(red);
      digitalWrite(__spi_latch,HIGH);
    }
  }
  digitalWrite(__display_enable,HIGH);    // disable display outside ISR
}


byte spi_transfer(byte data) {
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  return SPDR;                    // return the received byte.

In particular. I’ve detected that the Servos will start working properly when I deactivate the setup_timer1 function in setup. So the timer is obviously the problem.

But from there I don’t know how to proceed. ¿Is it possible to modify the code of the servos so that they can function along the matrix, or is it simpler to control the matrix from SerialEvent while the servos run from the loop?

Funciones_Matriz.ino (10.2 KB)

MatrizRGB.ino (2.67 KB)

So the timer is obviously the problem.

Yes. The Servo library uses the timer you are diddling with. You can either use a different timer for your use, or use the ServoTimer2 library, which uses a different timer for the servos.