Electronic – arduino – Why does the accuracy of the camera drop when I start using no-ops as delays

arduinoassemblycameraclock

I'm using an Arduino Mega to run three TSL1401R-LF Linear Scan Cameras in parallel. I got everything working and the camera were giving me different results based on how much light was hitting them (i.e. lots of light gave me a high number and little light gave me a smaller number).

However when I attempted to increase the FPS of the cameras by reducing the delays using no-ops the accuracy fell dramatically and I have no idea why. According to the datasheet the minimum delays for the CLK impulse is 50 ns and a no-op causes a delay of 62.5 ns so there should't be a problem. Anyone on here have and idea as to why this could be happening?

Here is my code before the no-ops:

void readPixels()  
{
  digitalWrite(SI, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(SI, LOW);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, LOW);
  delayMicroseconds(delayTime);

  for(int i = 0; i < 128; i++)
  { 
    digitalWrite(CLK, HIGH);
    pixelsArray1[i]=analogRead(Cam1Aout);
    pixelsArray2[i]=analogRead(Cam2Aout);
    pixelsArray3[i]=analogRead(Cam3Aout);
    delayMicroseconds(delayTime);
    digitalWrite(CLK, LOW);
    delayMicroseconds(delayTime);
  }

  delayMicroseconds(20);

}

OUTPUT:
Camera 1: 295, 319, 353, 387, 422, 458, 483, 499, 515, 527, 540, 545, 556, 562, 572, 575, 585, 590, 596, 598, 606, 603, 591, 589, 608, 621, 635, 636, 646, 652, 664, 670, 681, 689, 699, 705, 715, 726, 730, 734, 742, 745, 750, 752, 760, 764, 769, 766, 768, 770, 775, 777, 792, 806, 828, 852, 880, 907, 931, 956, 989, 1016, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 980, 986, 935, 935, 893, 892, 856, 847, 812, 801, 774, 760, 731, 713, 683, 647, 605, 564, 513, 470, 410, 369, 323, 289, 347, 376, 
Camera 2: 346, 368, 396, 419, 446, 462, 480, 496, 516, 531, 549, 559, 571, 579, 593, 600, 611, 619, 628, 636, 647, 651, 660, 667, 676, 679, 687, 696, 704, 710, 719, 725, 732, 735, 743, 743, 752, 758, 764, 768, 775, 777, 783, 788, 793, 798, 803, 806, 809, 814, 818, 822, 827, 831, 831, 833, 836, 839, 841, 839, 843, 843, 844, 839, 841, 836, 831, 830, 831, 830, 831, 834, 841, 847, 861, 867, 880, 894, 902, 911, 918, 935, 940, 956, 960, 976, 973, 991, 984, 1007, 998, 1020, 998, 1019, 992, 1014, 986, 997, 964, 969, 937, 937, 908, 910, 878, 875, 843, 838, 808, 797, 768, 750, 720, 696, 667, 639, 611, 582, 556, 524, 499, 471, 449, 423, 399, 371, 396, 399, 
Camera 3: 472, 491, 507, 512, 526, 551, 564, 572, 583, 588, 583, 586, 587, 593, 603, 604, 604, 608, 611, 617, 617, 621, 625, 629, 635, 641, 635, 645, 661, 668, 671, 675, 678, 680, 685, 688, 688, 690, 691, 694, 696, 701, 701, 704, 699, 706, 705, 706, 713, 715, 718, 719, 719, 719, 720, 721, 723, 731, 737, 736, 739, 743, 748, 751, 755, 758, 760, 763, 766, 768, 769, 773, 775, 777, 777, 780, 787, 791, 790, 787, 781, 779, 769, 763, 760, 758, 755, 750, 743, 741, 744, 748, 743, 740, 750, 755, 774, 783, 790, 797, 802, 810, 807, 818, 806, 807, 796, 796, 785, 777, 759, 748, 728, 715, 696, 681, 664, 647, 625, 606, 579, 558, 536, 508, 484, 467, 432, 427, 
Runetime: 2121

Here it is after the no-ops are added:

void readPixels()  
{
  digitalWrite(SI, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(SI, LOW);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, LOW);
  delayMicroseconds(delayTime);

  for(int i = 0; i < 128; i++)
  { 
    digitalWrite(CLK, HIGH);
    pixelsArray1[i]=analogRead(Cam1Aout);
    pixelsArray2[i]=analogRead(Cam2Aout);
    pixelsArray3[i]=analogRead(Cam3Aout);
    __asm__("nop\n\t");
    digitalWrite(CLK, LOW);
    __asm__("nop\n\t");
  }

  delayMicroseconds(20);

}

OUTPUT:
Camera 1: 147, 141, 142, 143, 145, 145, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, 145, 145, 143, 145, 143, 146, 146, 145, 145, 144, 147, 147, 147, 147, 148, 147, 147, 147, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 148, 147, 147, 148, 147, 151, 152, 153, 154, 156, 156, 158, 158, 159, 161, 162, 163, 165, 166, 167, 167, 168, 169, 167, 172, 174, 174, 174, 174, 175, 176, 176, 177, 177, 179, 179, 179, 179, 179, 178, 178, 176, 175, 174, 172, 172, 170, 168, 167, 165, 163, 162, 161, 159, 158, 156, 154, 155, 152, 151, 150, 148, 146, 146, 143, 143, 141, 139, 137, 135, 131, 129, 127, 125, 122, 120, 140, 172, 
Camera 2: 162, 161, 164, 164, 167, 166, 165, 167, 169, 167, 170, 171, 171, 169, 172, 171, 172, 171, 172, 172, 172, 172, 173, 172, 173, 172, 174, 173, 174, 173, 174, 174, 176, 174, 175, 170, 175, 174, 176, 175, 185, 175, 176, 175, 176, 175, 176, 176, 176, 176, 176, 176, 177, 176, 177, 176, 176, 176, 177, 176, 177, 176, 177, 176, 176, 176, 176, 176, 176, 175, 176, 175, 176, 176, 177, 177, 179, 177, 179, 179, 179, 179, 181, 181, 183, 183, 184, 184, 185, 185, 186, 185, 187, 186, 187, 187, 188, 185, 186, 184, 185, 183, 183, 181, 181, 179, 179, 176, 176, 174, 174, 172, 171, 170, 167, 164, 164, 162, 161, 159, 159, 156, 157, 154, 153, 152, 169, 198, 
Camera 3: 185, 187, 188, 191, 189, 190, 192, 192, 193, 193, 192, 194, 194, 194, 195, 199, 196, 196, 196, 197, 199, 198, 198, 198, 199, 199, 199, 199, 196, 201, 201, 201, 201, 201, 202, 203, 202, 202, 203, 203, 204, 204, 204, 203, 204, 204, 204, 204, 204, 204, 205, 205, 205, 206, 206, 206, 205, 206, 206, 206, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 208, 207, 209, 209, 208, 208, 209, 209, 207, 208, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 208, 209, 209, 209, 211, 211, 211, 211, 211, 211, 211, 210, 210, 209, 209, 207, 207, 206, 206, 204, 203, 203, 201, 199, 200, 198, 195, 195, 195, 193, 167, 179, 
Runetime: 1987

Here it is with me using While Loops:

void readPixels()  
{
  digitalWrite(SI, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(delayTime/2);
  digitalWrite(SI, LOW);
  delayMicroseconds(delayTime/2);
  digitalWrite(CLK, LOW);
  delayMicroseconds(delayTime);

  int i = 0;
  while(i < 128)
  {
    i++;
    digitalWrite(CLK, HIGH);
    pixelsArray1[i]=analogRead(Cam1Aout);
    pixelsArray2[i]=analogRead(Cam2Aout);
    pixelsArray3[i]=analogRead(Cam3Aout);
    digitalWrite(CLK, LOW);
  }

  delayMicroseconds(20);

}

OUTPUT:
Camera 1: 224, 161, 172, 179, 185, 198, 199, 203, 206, 208, 208, 211, 212, 213, 214, 216, 216, 217, 217, 218, 217, 219, 219, 216, 215, 217, 220, 222, 223, 223, 224, 226, 225, 229, 231, 231, 232, 235, 235, 236, 237, 238, 240, 240, 240, 240, 241, 242, 242, 242, 242, 243, 243, 246, 248, 252, 255, 262, 266, 271, 276, 281, 287, 291, 296, 304, 307, 314, 319, 326, 332, 331, 337, 337, 335, 352, 359, 359, 359, 361, 366, 371, 371, 372, 376, 382, 384, 384, 382, 380, 380, 377, 372, 366, 361, 355, 351, 344, 339, 331, 323, 318, 312, 307, 301, 294, 290, 284, 280, 273, 268, 263, 257, 252, 248, 241, 231, 227, 219, 209, 199, 191, 182, 172, 163, 155, 147, 176, 
Camera 2: 216, 193, 196, 203, 207, 212, 216, 219, 222, 223, 227, 231, 231, 234, 236, 238, 239, 241, 242, 242, 244, 247, 247, 248, 249, 252, 252, 252, 254, 255, 258, 259, 259, 259, 260, 262, 262, 263, 263, 265, 272, 268, 267, 268, 268, 270, 270, 271, 271, 272, 273, 274, 275, 275, 275, 276, 276, 277, 277, 278, 277, 280, 278, 278, 277, 278, 276, 276, 275, 275, 275, 275, 276, 277, 278, 280, 282, 285, 287, 289, 291, 294, 295, 299, 301, 304, 306, 310, 312, 313, 316, 319, 319, 321, 322, 323, 323, 322, 319, 318, 315, 312, 308, 305, 302, 298, 294, 289, 284, 280, 275, 270, 263, 257, 251, 244, 238, 232, 227, 223, 216, 211, 206, 202, 197, 193, 188, 207, 
Camera 3: 0, 231, 235, 238, 240, 243, 247, 250, 252, 254, 255, 255, 255, 255, 257, 259, 260, 260, 260, 262, 260, 263, 264, 265, 266, 267, 268, 268, 269, 273, 274, 276, 275, 276, 277, 278, 278, 279, 279, 280, 280, 280, 281, 281, 281, 281, 283, 283, 283, 284, 284, 285, 285, 285, 286, 286, 286, 286, 287, 289, 289, 289, 290, 291, 291, 292, 293, 293, 294, 294, 295, 295, 295, 295, 295, 296, 297, 298, 299, 299, 298, 297, 296, 295, 294, 294, 292, 292, 291, 290, 289, 291, 291, 290, 289, 291, 292, 295, 298, 300, 302, 304, 304, 307, 307, 307, 305, 304, 304, 303, 300, 297, 294, 289, 287, 283, 280, 275, 272, 269, 263, 259, 255, 252, 246, 241, 237, 212, 
Runetime: 1991

Some notes:

  • I've optimized the analogRead(); method with prescalers so they are faster than usual.

  • While the output of the second code does show some difference when I hold an object in the line of site of the cameras it is a much smaller difference and only works when I'm holding it directly in front of the cameras.

Best Answer

What most probably happened is the compiler decided to optimize your code and threw those nop's away. You should force the compiler to keep your assembly intact by defining it volatile:

__asm__ __volatile__ ("nop\n\t");

Alternatively, you could make a delay by doing something useful, for example:

int i = 0;
while(i < 128)
{
i++;
digitalWrite(CLK, HIGH);
pixelsArray1[i]=analogRead(Cam1Aout);
pixelsArray2[i]=analogRead(Cam2Aout);
pixelsArray3[i]=analogRead(Cam3Aout);
digitalWrite(CLK, LOW);
}

PS. The drop in sensitivity you are seeing may well be normal. Your datasheet says:

The minimum integration time for any given array is determined by time required to clock out all the pixels in the array and the time to discharge the pixels. The time required to discharge the pixels is a constant. Therefore, the minimum integration period is simply a function of the clock frequency and the number of pixels in the array. A slower clock speed increases the minimum integration time and reduces the maximum light level for saturation on the output. The minimum integration time shown in this data sheet is based on the maximum clock frequency of 8 MHz.

Since your optimized code runs faster, there is less time left for integration, which reduces the output value.

Also, try adding a delay after digitalWrite(CLK, HIGH); to respect the ts time mentioned in the waveform on page 5.