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
If noInterrupts() is present, I get a few characters and then the serial write appears to freeze
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");
}
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.
If noInterrupts() is commented out, the serial write functions properly
// ***********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).
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.
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.
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....