noInterrupts() and Serial.write issues

In my program I am getting two different behaviors regarding Serial writes depending if noInterrupts() is present or not, even with Interrupts() not present in the code

  1. If noInterrupts() is present, I get a few characters and then the serial write appears to freeze
  2. If noInterrupts() is commented out, the serial write functions properly

Any idea what is going on? Are serial writes connected to interrupts somehow?

What I'm trying to do is execute an interrupt on an ADC complete while it is free running.
With a prescalar of 128 on an Arduino Uno (16MHz), I expect an interrupt every 100us or so (since it takes 13 clock cycles).

In case anyone wants to see code, I put a stripped down version below. Oh, and I'm using version 1.03 of the IDE

Thanks in advance,
memotick

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 

// Every Arduino program must have a setup section
void setup() {

  // ***********here is the problem area *********
  // noInterrupts(); 
  // ***********here is the problem area *********

  //clear ADCSRA and ADCSRB registers
  ADCSRA = 0;
  ADCSRB = 0;

  // ADCSRA: page 265
  // ADEN: Enable ADC
  sbi(ADCSRA, ADEN);
  // ADATE: ADC auto trigger enable
  sbi(ADCSRA, ADATE);

  // ADMUX page 264
  // select ADC0 channel
  cbi(ADMUX, MUX3);
  cbi(ADMUX, MUX2);
  cbi(ADMUX, MUX1);
  cbi(ADMUX, MUX0);

  // Quiet ADC inputs
  // Check page 266 of the ATmega328p datasheet 
  // for more information.
  sbi(DIDR0,ADC5D);
  sbi(DIDR0,ADC4D);
  sbi(DIDR0,ADC3D);
  sbi(DIDR0,ADC2D);
  sbi(DIDR0,ADC1D);
  sbi(DIDR0,ADC0D);

  // Internal pull-ups interfere with the ADC. disable the pull-up on the
  // pin ifit's being used for ADC. either writing 0 to the port register
  // or setting it to output should be enough to disable pull-ups.
  DDRC = 0x00;

  // Set ADC prescalar to 128.  Thus one conversion every
  // (128*13)/16MHz = 104us
  sbi(ADCSRA, ADPS2);
  sbi(ADCSRA, ADPS1);
  sbi(ADCSRA, ADPS0);

  // ADSCRB: page 267
  // ADTST2:0 : ADC trigger select 000=Free running
  cbi(ADCSRB,ADTS2);
  cbi(ADCSRB,ADTS1);
  cbi(ADCSRB,ADTS0);

  Serial.begin(57600);  

  // ADCSRA: page 265
  // ADSC: ADC start conversion and allow ISR to run
  sbi(ADCSRA, ADSC);

  //sei();//enable interrupts

}

////Interrupt Service Routine (ISR)
ISR(ADC_vect) {
  //when new ADC value ready, do something here
}

void loop() {

  Serial.write("Made it in the loop\n");
}

Serial data is sent using interrupts. Turning interrupts off prevents sending serial data. There's nothing complicated about it.

  1. If noInterrupts() is present, I get a few characters and then the serial write appears to freeze

This is normal behaviour. The hardware serial library uses interrupts to move data to and from software memory buffers and the USART hardware, so as nointerrupts disables ALL interrupts serial data stops, millis() timer interrupts stops and any user interrupts or pin change interrupts you are using are all prevented from execution until you issue a Interrupts command.

  1. If noInterrupts() is commented out, the serial write functions properly

Again as explained above.

Lefty

Apart from this issue:

  // ***********here is the problem area *********
  // noInterrupts(); 
  // ***********here is the problem area *********

...

  Serial.begin(57600);  

  // ADCSRA: page 265
  // ADSC: ADC start conversion and allow ISR to run
  sbi(ADCSRA, ADSC);

  //sei();//enable interrupts

You are hoping for an ADC interrupt but have interrupts off (if you call noInterrupts).

Nick,
Wow, you pay attention to detail!

hi there,

Iam confused.
in loop where I print "counter" Serial.println works
but when I press 'a' evrything stops and Iam not able press 's' to start again.
thx in advance

volatile uint32_t counter = 0;
long timer = 0;
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {

	Serial.begin(115200);
	pinMode(2, INPUT);
	pinMode(3, INPUT);
	attachInterrupt(0, rpm, RISING);
	attachInterrupt(1, rpm2, RISING);
	timer = millis();
	
}
void rpm()
{
	counter++;
}
void rpm2()
{
	counter++;
}
void loop() {
	serialEvent();
	if (stringComplete) {
		
		Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
}

if ( millis() - timer >= 1000 )
{
    cli();//noInterupts
    Serial.println( "#####################" );
    Serial.println(counter);
    timer = millis();
    counter = 0;
    sei();//Interupts
}

}
void serialEvent() {
	while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == 'a') {
    	cli();
    }
    if (inChar == 's') {
    	sei();
    }

    if (inChar == '\r') {
    	stringComplete = true;
    }
}
}

Serial output is interrupt driven. When print() is called, it transfers data to a buffer, if there is room. If there is not, print() waits for there to be room.

Room is made by shifting data out, in an ISR routine. With interrupts disabled, that doesn't happen, so room is never made.

The moral of the story? Do NOT call Serial.print() while interrupts are disabled. Ever!

With 1.6.5, I think that code would work - the current version of the Arduino core, if the buffer is full, will check whether interrupts are disabled, and if they are, will busy-wait for it, instead of just blocking forever like 1.0.x versions of Arduino do.

(see https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp - it's explained in the comments)

That doesn't change the fact that you should not be using serial with interrupts disabled; turning off interrupts in general should be done only when absolutely necessary, and then, only briefly.

well, I got that idea from http://www.amazon.com/Professional-Android-Accessory-Programming-Arduino/dp/1118454766/ref=sr_1_sc_1?ie=UTF8&qid=1441132800&sr=8-1-spell&keywords=profesional+android+open+accessory

void loop() {
if(millis() - timer >= PERIOD) {
noInterrupts(); // disable interrupts
Serial.print("Wheel: "); Serial.println(counterWheel);
counterWheel = 0;
Serial.print("Pedal: "); Serial.println(counterPedal);
counterPedal = 0;
timer = millis();
interrupts(); // enable interrupts
}
}

is there any way to send info and not be interrupted by Interrupts()?

Marrek:
well, I got that idea from http://www.amazon.com/Professional-Android-Accessory-Programming-Arduino/dp/1118454766/ref=sr_1_sc_1?ie=UTF8&qid=1441132800&sr=8-1-spell&keywords=profesional+android+open+accessory

void loop() {

if(millis() - timer >= PERIOD) {
noInterrupts(); // disable interrupts
Serial.print("Wheel: "); Serial.println(counterWheel);
counterWheel = 0;
Serial.print("Pedal: "); Serial.println(counterPedal);
counterPedal = 0;
timer = millis();
interrupts(); // enable interrupts
}
}




is there any way to send info and not be interrupted by Interrupts()?

First, that code was written by someone who clearly had no idea what he was doing, so I would not use that as a model.

Second, why on earth do you care?? The interrupts are totally transparent to you, and if you're doing something where the interrupts cause you a problem, odds are you are doing something wrong....

Regards,
Ray L.