I don't know why each interation of this loop takes different times (look at the clock):
long result = 0;
int bit_status;
for (int i = 23; i >= 0; --i) {
PORTD |= (1 << clk_pin);//WRITE HIGH ON CLOCK
bit_status = PINK & (1 << dat_pin);//READ DATA <-----------------------------
if(bit_status) result |= (1L<<i);//<-----------------------------------------------------
PORTD &= ~(1 << clk_pin);//WRITE LOW ON CLOCK
}
PORTD |= (1 << clk_pin);//WRITE HIGH ON CLOCK
__asm__("nop");
__asm__("nop");
PORTD &= ~(1 << clk_pin);//WRITE LOW ON CLOCK
And, if I use this other code (which is worse) i get that very interesting shape in which every iteration takes less time:
long result = 0;
int bit_status;
for (int i = 23; i >= 0; --i) {
PORTD |= (1 << clk_pin);//WRITE HIGH ON CLOCK
result |= ((PINK >> dat_pin) & 1L) << i;//<------------------------------------------
PORTD &= ~(1 << clk_pin);//WRITE LOW ON CLOCK
}
PORTD |= (1 << clk_pin);//WRITE HIGH ON CLOCK
__asm__("nop");
__asm__("nop");
PORTD &= ~(1 << clk_pin);//WRITE LOW ON CLOCK
Me neither, but it might be related to something in your sketch that was left out of your post, and this may in turn depend on the hardware of the unspecified board you're using.
Thank you for your answer. The board is the MEGA (it was specified in the title).
The entire code is:
#define LOADCELL_1_SCK_PIN 18//VI D3
#define LOADCELL_2_SCK_PIN 19//HI D2
#define LOADCELL_3_SCK_PIN 20//HD D1
#define LOADCELL_4_SCK_PIN 21//VD D0
#define LOADCELL_1_DOUT_PIN A12//VI K4
#define LOADCELL_2_DOUT_PIN A13//HI K5
#define LOADCELL_3_DOUT_PIN A14//HD K6
#define LOADCELL_4_DOUT_PIN A15//VD K7
const int dat_pin = 4;//K
const int clk_pin = 3;//D
/*#define BIT_CHECK(port, pin) ((port) & (1 << (pin)))
result |= (BIT_CHECK(PINK, dat_pin) != 0) << i;*/
void setup() {
pinMode(LOADCELL_1_DOUT_PIN, INPUT);
pinMode(LOADCELL_2_DOUT_PIN, INPUT);
pinMode(LOADCELL_3_DOUT_PIN, INPUT);
pinMode(LOADCELL_4_DOUT_PIN, INPUT);
pinMode(LOADCELL_1_SCK_PIN, OUTPUT);
pinMode(LOADCELL_2_SCK_PIN, OUTPUT);
pinMode(LOADCELL_3_SCK_PIN, OUTPUT);
pinMode(LOADCELL_4_SCK_PIN, OUTPUT);
pinMode(A8, OUTPUT);//K0
Serial.begin(115200);
}
//datasheet nos da los tiepos mĂnimos (200ns).
void loop() {
if( !(PINK & (1 << dat_pin)) ) {//READ
//PORTK |= 1;//A8 HIGH
long result = 0;
int bit_status;
//Las lecturas no pueden ser interrumpidas
//noInterrupts(); //quizás poner prioridad top.
//noInterrupts();
for (int i = 23; i >= 0; --i) {
PORTD |= (1 << clk_pin);//WRITE HIGH
//result |= (PINK & (1 << dat_pin))?(1L<<i):0; //READ
//result |= ((PINK & (1 << dat_pin))?1L:0)<<i; //READ PEOR
//result |= ((PINK >> dat_pin) & 1L) << i;//MUCHO PEOR
//result |= (long)((PINK & (1 << dat_pin)) != 0) << i; //peor
bit_status = PINK & (1 << dat_pin); //esta es la linea que tarda más si antes recibà un uno.
if(bit_status)
result |= (1L<<i);
//result |= bit_status?(1L<<i):0;
PORTD &= ~(1 << clk_pin);//WRITE LOW
}
//quizas le cuesta leer
//falla la prediccion
//
//Ciclos extra que determinan la ganancia de la iguiente lectura: 1 ciclo = 128.
PORTD |= (1 << clk_pin);//WRITE HIGH
__asm__("nop");
__asm__("nop");//dos está bien.
PORTD &= ~(1 << clk_pin);//WRITE LOW
//Volvemos a habilitar interrupts.
//interrupts();
//Rellena con unos o ceros por signo.
result |= (result & 1UL << 23 ? 0xFFUL : 0x00UL) << 24;
//PORTK &= ~1;//A8 LOW
Serial.println(result);
}
}
You have ALL the the reason. If I delete the line "Serial.println(result); " it all works fine. WHY??
Plus, I can't check the data :..(
How can I maintain the Serial.print without increasing times?
Well I don't care if the Serial takes its time AFTER reading all the Data. What I don't want is that it makes the iterations that are before it, last longer I don't know why...
If you want Serial to consistently take the same amount of time to send data, you will need to always send the same number of characters, as well as using Serial.flush()
As The iterations only get "extended" if the previous data bit received was HIGH, I don't don't think it is the Serial actually sending data what slows the iteration.
What if you uncomment your noInterrupts() and interrupt() statements.
The Serial.println() call itself doesn't take much time. but the actual transfer is done by interrupts.
Well, since the problem went away when you removed the Serial print, evidently it's related to the latter. And yes, I think it's the ISR that handles the UART communication that messes up your timing.
In your place I'd try putting a Serial.flush() followed by a delay(50) or so after the Serial.println and see if that helps. If so, you know you need to somehow allow the Serial buffer to do its thing before you do critical timing stuff again.
Alternatively you could postpone the Serial.print to a moment when you expect the controller to have more time.
Another solution involves moving from the Mega to something that can send UART stuff using DMA, but frankly, that's likely overkill.
Btw, is it intentonal that your critical timing routine runs as long as the input pin is LOW, and not just once?
I have removed Serial.begin() and obviously the Serial.println() and it continues "extending" the readings (I have declared result as a global):
#define LOADCELL_1_SCK_PIN 18//VI D3
#define LOADCELL_2_SCK_PIN 19//HI D2
#define LOADCELL_3_SCK_PIN 20//HD D1
#define LOADCELL_4_SCK_PIN 21//VD D0
#define LOADCELL_1_DOUT_PIN A12//VI K4
#define LOADCELL_2_DOUT_PIN A13//HI K5
#define LOADCELL_3_DOUT_PIN A14//HD K6
#define LOADCELL_4_DOUT_PIN A15//VD K7
const int dat_pin = 4;//K
const int clk_pin = 3;//D
/*#define BIT_CHECK(port, pin) ((port) & (1 << (pin)))
result |= (BIT_CHECK(PINK, dat_pin) != 0) << i;*/
void setup() {
pinMode(LOADCELL_1_DOUT_PIN, INPUT);
pinMode(LOADCELL_2_DOUT_PIN, INPUT);
pinMode(LOADCELL_3_DOUT_PIN, INPUT);
pinMode(LOADCELL_4_DOUT_PIN, INPUT);
pinMode(LOADCELL_1_SCK_PIN, OUTPUT);
pinMode(LOADCELL_2_SCK_PIN, OUTPUT);
pinMode(LOADCELL_3_SCK_PIN, OUTPUT);
pinMode(LOADCELL_4_SCK_PIN, OUTPUT);
pinMode(A8, OUTPUT);//K0
//Serial.begin(9600);
}
//datasheet nos da los tiepos mĂnimos (200ns).
long result;
void loop() {
if( !(PINK & (1 << dat_pin)) ) {//READ
//PORTK |= 1;//A8 HIGH
result = 0;
int bit_status;
//Las lecturas no pueden ser interrumpidas
//noInterrupts(); //quizás poner prioridad top.
//noInterrupts();
for (int i = 23; i >= 0; --i) {
PORTD |= (1 << clk_pin);//WRITE HIGH
//result |= (PINK & (1 << dat_pin))?(1L<<i):0; //READ
//result |= ((PINK & (1 << dat_pin))?1L:0)<<i; //READ PEOR
//result |= ((PINK >> dat_pin) & 1L) << i;//MUCHO PEOR
//result |= (long)((PINK & (1 << dat_pin)) != 0) << i; //peor
bit_status = PINK & (1 << dat_pin); //esta es la linea que tarda más si antes recibà un uno.
if(bit_status)
result |= (1L<<i);
//result |= bit_status?(1L<<i):0;
PORTD &= ~(1 << clk_pin);//WRITE LOW
}
//quizas le cuesta leer
//falla la prediccion
//
//Ciclos extra que determinan la ganancia de la iguiente lectura: 1 ciclo = 128.
PORTD |= (1 << clk_pin);//WRITE HIGH
__asm__("nop");
__asm__("nop");//dos está bien.
PORTD &= ~(1 << clk_pin);//WRITE LOW
//Volvemos a habilitar interrupts.
//interrupts();
//Rellena con unos o ceros por signo.
result |= (result & 1UL << 23 ? 0xFFUL : 0x00UL) << 24;
//PORTK &= ~1;//A8 LOW
}
//Serial.println(result);
}
So it was a coincidence that removing the print line it got corrected. It's not the Serial (it would have been "corrected" with the noInterrupts() I think).
A simple sensor I don't think you will know about it. You send it clock signals and it answers you as we see in the Data line of the pictures. That's not the problem: we can see it answers correctly. And even when more than one consecutive data bit is HIGH (an so HIGH voltage level is maintained for some time), we also get the problem => for sure the sensor it's not the problem.