My code needs Serial.begin to work but I do not need Serial support in my code

The code here below works fine. It generates a pulse place modulation signal with 8 channels.

HOWEVER

If you comment out the Serial.begin(9600) … it does not generate the last (the 8th) channel. It in fact becomes unstable … an 8th channel comes up and moves from a much too small to a much too big pulse and after that you have a perfect 7 channel PPM signal…and after a very long time the 8th channel comes up again.

Anyone who has a hint?… because I’ve now tried many things for 7 hours and I am lacking inspiration.

Jan Huygh

PS: I had the Serial.begin in my code for debugging

//Convenience macros
#define TC1_ConnectToPrescaler_8 TCCR1B &= ~((1<<CS12) | (1<<CS10)) ; TCCR1B |= (1<<CS11)
#define TC1_ClearOnCompareMatchWithOCR1A TCCR1A &= ~((1<<WGM11)|(1<<WGM10)); TCCR1B &= ~(1<<WGM13); TCCR1B |= (1<<WGM12)
#define TC1_EnableInterruptOnCompareMatchWithOCR1A TIMSK1 |= (1<<OCIE1A)
#define TC1_EnableInterruptOnCompareMatchWithOCR1B TIMSK1 |= (1<<OCIE1B)
#define TC1_DisableInterruptOnCompareMatchWith0CR1B TIMSK1 &= ~(1<<OCIE1B)

const byte PPM_Pin = 12;
volatile byte PPM_Progress = 0;
volatile word CHX_Pulse[7];

void setup () {
  Serial.begin(9600);
  pinMode(PPM_Pin, OUTPUT); 
  TC1_ConnectToPrescaler_8; //1 count = 0,5 µs
  TC1_ClearOnCompareMatchWithOCR1A;
  TC1_EnableInterruptOnCompareMatchWithOCR1A;
  OCR1A = 40000; 
  for (byte i = 0 ; i<8 ; i++){
    CHX_Pulse[i] = 800 + i*200;
  }
}

void loop () {
}

ISR(TIMER1_COMPA_vect){
  digitalWrite(PPM_Pin, LOW);
  PPM_Progress = 1;
  OCR1B = 800; 
  TC1_EnableInterruptOnCompareMatchWithOCR1B; 
  return;
}

ISR(TIMER1_COMPB_vect){
  switch (PPM_Progress) {
    case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15: case 17:
      digitalWrite(PPM_Pin, HIGH);
      OCR1B = OCR1B + CHX_Pulse[PPM_Progress/2]*2;
      break;
    case 2: case 4: case 6: case 8: case 10: case 12: case 14: case 16:
      digitalWrite(PPM_Pin,LOW);
      OCR1B = OCR1B + 800;
  }
  PPM_Progress++;
  if (PPM_Progress == 18) {
    PPM_Progress = 0;
    TC1_DisableInterruptOnCompareMatchWith0CR1B;
  }
  return;
}

Looks like a nasty problem. All I can guess is that the serial port initialisation is doing something necessary to the timer or interrupt configuration, which your subsequent use of interrupts depends on. But I have no idea what that something might be.

Like PeterH, I suspect that the Serial.begin is causing something to be initialized a specific way that allows your code to be run. Unfortunately, again like PeterH, I don't know what it is.

However, your code seems to indicate you are comfortable with lower level control of the IC (like manipulating registers). Therefore, if you don't get a response from someone more knowledgeable, my advice is to poke around the Serial library to see what exactly is being initialized then duplicate that in your code. Then via experimentation and process of elimination you can figure-out what is enabling your program to work correctly and only include that in your final program.

The code now works... two things had to be done...

  1. The array was incorrectly dimensioned in the beginning of the code (embarrassing)... I also changed the way the array is used in the OCR1B ISR.
  2. In the OCR1A interrupt routine you needs to clear the interrupt. And to clear you need to write a 1 to the corresponding bit (so I write 255 to TIFR1) before you enable the interrupts again.

The now well working code

//Convenience macros
#define TC1_ConnectToPrescaler_8 TCCR1B &= ~((1<<CS12) | (1<<CS10)) ; TCCR1B |= (1<<CS11)
#define TC1_ClearOnCompareMatchWithOCR1A TCCR1A &= ~((1<<WGM11)|(1<<WGM10)); TCCR1B &= ~(1<<WGM13); TCCR1B |= (1<<WGM12)
#define TC1_EnableInterruptOnCompareMatchWithOCR1A TIMSK1 |= (1<<OCIE1A)
#define TC1_EnableInterruptOnCompareMatchWithOCR1B TIMSK1 |= (1<<OCIE1B)
#define TC1_DisableInterruptOnCompareMatchWith0CR1B TIMSK1 &= ~(1<<OCIE1B)

const byte PPM_Pin = 12;
volatile byte PPM_Progress = 0;
volatile word CHX_Pulse[8];

void setup () {
  pinMode(13,OUTPUT);
  pinMode(PPM_Pin, OUTPUT); 
  TC1_ConnectToPrescaler_8; //1 count = 0,5 µs
  TC1_ClearOnCompareMatchWithOCR1A;
  TC1_EnableInterruptOnCompareMatchWithOCR1A;
  OCR1A = 40000;
  for (byte i = 0 ; i < 8 ; i++){
    CHX_Pulse[i] = 800 + i*200;
  }
}

void loop () {
}

ISR(TIMER1_COMPA_vect){
  digitalWrite(PPM_Pin, LOW);
  PPM_Progress = 1;
  OCR1B = 800; 
  TIFR1 = 255;
  TC1_EnableInterruptOnCompareMatchWithOCR1B;
  digitalWrite(13,HIGH);
  digitalWrite(13,LOW); 
  return;
}

ISR(TIMER1_COMPB_vect){
  switch (PPM_Progress) {
    case 1: case 3: case 5: case 7: case 9: case 11: case 13: case 15: case 17:
      digitalWrite(PPM_Pin, HIGH);
      OCR1B = OCR1B + CHX_Pulse[((PPM_Progress + 1)/2) - 1]*2;
      break;
    case 2: case 4: case 6: case 8: case 10: case 12: case 14: case 16:
      digitalWrite(PPM_Pin,LOW);
      OCR1B = OCR1B + 800;
  }
  PPM_Progress++;
  if (PPM_Progress == 18) {
    TC1_DisableInterruptOnCompareMatchWith0CR1B;
  }
  return;
}

Great, I'm glad you got it working without all the extra overhead of the Serial library. :slight_smile:

Serial begin was creating a buffer that that you never used, bu that allocated memory kept your code from clobbering another value...