digitalRead(16) always returning 0 when using SPI?

Status
Not open for further replies.

local_dani_21

Well-known member
Hi

I'm using a teensy 3.1 to drive three TFT's over (hardware-line-driven) SPI. That works like a charm.
However, to my device, I have also a pushbutton attached (with 10k pullup resistor), connected to pin 16.
However, when running the following code, digitalRead(16) always returns 0.
Code:
    #include <SPI.h>
    #include "Adafruit_GFX.h"
    #include "Adafruit_RA8875.h"
    #include <SD.h>
    #define sd_cs 10
    #define tasten_pin 16


    // Library only supports hardware SPI at this time
    // Connect SCLK to UNO Digital #13 (Hardware SPI clock)
    // Connect MISO to UNO Digital #12 (Hardware SPI MISO)
    // Connect MOSI to UNO Digital #11 (Hardware SPI MOSI)
    #define RA8875_CS 9
    #define RA8875_CS_2 6
    #define RA8875_CS_3 2
    #define RA8875_RESET 3

    Adafruit_RA8875 tft1 = Adafruit_RA8875(RA8875_CS);
    Adafruit_RA8875 tft2 = Adafruit_RA8875(RA8875_CS_2);
    Adafruit_RA8875 tft3 = Adafruit_RA8875(RA8875_CS_3);
    uint16_t tx, ty;



    void setup()
    {
      Serial.begin(57600);
      while(!Serial){}

      if (!SD.begin(sd_cs))
      {
        Serial.println("SD initialization failed!");
        return;
      }

      Serial.println("SD initialization done.");
      Serial.println("Press the Button!");
      while(digitalRead(16) == LOW){} // is low forever ...

      reset_tfts(RA8875_RESET); // Resetting manually to be able to use a common reset-line for all TFT's

      Serial.println("RA8875 1 start");
      /* Initialise the display using 'RA8875_480x272' or 'RA8875_800x480' */
      if (!tft1.begin_without_reset(RA8875_800x480)) {
        Serial.println("RA8875 1 Not Found!");
        while (1);
      }
      Serial.println("Found RA8875");

      Serial.println("RA8875 2 start");
      /* Initialise the display using 'RA8875_480x272' or 'RA8875_800x480' */
      if (!tft2.begin_without_reset(RA8875_800x480)) {
        Serial.println("RA8875 2 Not Found!");
        while (1);
      }
      Serial.println("Found RA8875 2");

      Serial.println("RA8875 3 start");
      /* Initialise the display using 'RA8875_480x272' or 'RA8875_800x480' */
      if (!tft3.begin_without_reset(RA8875_800x480)) {
        Serial.println("RA8875 3 Not Found!");
        while (1);
      }
      Serial.println("Found RA8875 3");

      tftSetup(&tft1);
      tftSetup(&tft2);
      tftSetup(&tft3);
    }

    void loop() {
      long int next_update;
      int update_intervall = 30000; // 30 Sekunden
      bmpDraw(&tft1, "1a.bmp", 0, 0); bmpDraw(&tft2, "1b.bmp", 0, 0); bmpDraw(&tft3, "1c.bmp", 0, 0);

      next_update = millis() + update_intervall;
      Serial.print(digitalRead(tasten_pin));
      Serial.print(" ");
      Serial.print(millis());
      Serial.println(next_update);
      while(millis() < next_update && digitalRead(tasten_pin) == HIGH){}
      bmpDraw(&tft1, "2a.bmp", 0, 0); bmpDraw(&tft2, "2b.bmp", 0, 0); bmpDraw(&tft3, "2c.bmp", 0, 0);

      next_update = millis() + update_intervall;
      Serial.print(digitalRead(tasten_pin));
      Serial.print(" ");
      Serial.print(millis());
      Serial.println(next_update);
      while(millis() < next_update && digitalRead(tasten_pin) == HIGH){}
      bmpDraw(&tft1, "3a.bmp", 0, 0); bmpDraw(&tft2, "3b.bmp", 0, 0); bmpDraw(&tft3, "3c.bmp", 0, 0);

      next_update = millis() + update_intervall;
      while(millis() < next_update && digitalRead(tasten_pin) == HIGH){}
      bmpDraw(&tft1, "4a.bmp", 0, 0); bmpDraw(&tft2, "4b.bmp", 0, 0); bmpDraw(&tft3, "4c.bmp", 0, 0);

      next_update = millis() + update_intervall;
      while(millis() < next_update && digitalRead(tasten_pin) == HIGH){}
    }

    void tftSetup(Adafruit_RA8875 *tft)
    {
      tft->displayOn(true);
      tft->GPIOX(true);      // Enable TFT - display enable tied to GPIOX
      tft->PWM1config(true, RA8875_PWM_CLK_DIV1024); // PWM output for backlight
      tft->PWM1out(255);

      // With hardware accelleration this is instant
      tft->fillScreen(RA8875_WHITE);
    }
    #define BUFFPIXEL 20

    void bmpDraw(Adafruit_RA8875 *tft, char *filename, int x, int y) {
      File     bmpFile;
      int      bmpWidth, bmpHeight;   // W+H in pixels
      uint8_t  bmpDepth;              // Bit depth (currently must be 24)
      uint32_t bmpImageoffset;        // Start of image data in file
      uint32_t rowSize;               // Not always = bmpWidth; may have padding
      uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
      uint16_t lcdbuffer[BUFFPIXEL];  // pixel out buffer (16-bit per pixel)
      uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
      boolean  goodBmp = false;       // Set to true on valid header parse
      boolean  flip    = true;        // BMP is stored bottom-to-top
      int      w, h, row, col;
      uint8_t  r, g, b;
      uint32_t pos = 0, startTime = millis();
      uint8_t  lcdidx = 0;
      boolean  first = true;

      if((x >= tft->width()) || (y >= tft->height())) return;

      Serial.println();
      Serial.print(F("Loading image '"));
      Serial.print(filename);
      Serial.println('\'');

      // Open requested file on SD card
      if ((bmpFile = SD.open(filename)) == NULL) {
        Serial.println(F("File not found"));
        return;
      }

      // Parse BMP header
      if(read16(bmpFile) == 0x4D42) { // BMP signature
        Serial.println(F("File size: "));
        Serial.println(read32(bmpFile));
        (void)read32(bmpFile); // Read & ignore creator bytes
        bmpImageoffset = read32(bmpFile); // Start of image data
        Serial.print(F("Image Offset: "));
        Serial.println(bmpImageoffset, DEC);

        // Read DIB header
        Serial.print(F("Header size: "));
        Serial.println(read32(bmpFile));
        bmpWidth  = read32(bmpFile);
        bmpHeight = read32(bmpFile);

        if(read16(bmpFile) == 1) { // # planes -- must be '1'
          bmpDepth = read16(bmpFile); // bits per pixel
          Serial.print(F("Bit Depth: "));
          Serial.println(bmpDepth);
          if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
            goodBmp = true; // Supported BMP format -- proceed!
            Serial.print(F("Image size: "));
            Serial.print(bmpWidth);
            Serial.print('x');
            Serial.println(bmpHeight);

            // BMP rows are padded (if needed) to 4-byte boundary
            rowSize = (bmpWidth * 3 + 3) & ~3;

            // If bmpHeight is negative, image is in top-down order.
            // This is not canon but has been observed in the wild.
            if(bmpHeight < 0) {
              bmpHeight = -bmpHeight;
              flip      = false;
            }

            // Crop area to be loaded
            w = bmpWidth;
            h = bmpHeight;
            if((x+w-1) >= tft->width())  w = tft->width()  - x;
            if((y+h-1) >= tft->height()) h = tft->height() - y;

            // Set TFT address window to clipped image bounds

            for (row=0; row<h; row++) { // For each scanline...
              // Seek to start of scan line.  It might seem labor-
              // intensive to be doing this on every line, but this
              // method covers a lot of gritty details like cropping
              // and scanline padding.  Also, the seek only takes
              // place if the file position actually needs to change
              // (avoids a lot of cluster math in SD library).
              if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
                pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
              else     // Bitmap is stored top-to-bottom
              pos = bmpImageoffset + row * rowSize;
              if(bmpFile.position() != pos) { // Need seek?
                bmpFile.seek(pos);
                buffidx = sizeof(sdbuffer); // Force buffer reload
              }

              for (col=0; col<w; col++) { // For each column...
                // Time to read more pixel data?
                if (buffidx >= sizeof(sdbuffer)) { // Indeed
                  // Push LCD buffer to the display first
                  if(lcdidx > 0) {
                    tft->drawPixel(col, row, lcdbuffer[lcdidx]);
                    lcdidx = 0;
                    first  = false;
                  }

                  bmpFile.read(sdbuffer, sizeof(sdbuffer));
                  buffidx = 0; // Set index to beginning
                }

                // Convert pixel from BMP to TFT format
                b = sdbuffer[buffidx++];
                g = sdbuffer[buffidx++];
                r = sdbuffer[buffidx++];
                lcdbuffer[lcdidx] = color565(r,g,b);
                tft->drawPixel(col, row, lcdbuffer[lcdidx]);
              } // end pixel

            } // end scanline

            // Write any remaining data to LCD
            if(lcdidx > 0) {
              tft->drawPixel(col, row, lcdbuffer[lcdidx]);
            }

            Serial.print(F("Loaded in "));
            Serial.print(millis() - startTime);
            Serial.println(" ms");

          } // end goodBmp
        }
      }

      bmpFile.close();
      if(!goodBmp) Serial.println(F("BMP format not recognized."));

    }

    // These read 16- and 32-bit types from the SD card file.
    // BMP data is stored little-endian, Arduino is little-endian too.
    // May need to reverse subscript order if porting elsewhere.

    uint16_t read16(File f) {
      uint16_t result;
      ((uint8_t *)&result)[0] = f.read(); // LSB
      ((uint8_t *)&result)[1] = f.read(); // MSB
      return result;
    }

    uint32_t read32(File f) {
      uint32_t result;
      ((uint8_t *)&result)[0] = f.read(); // LSB
      ((uint8_t *)&result)[1] = f.read();
      ((uint8_t *)&result)[2] = f.read();
      ((uint8_t *)&result)[3] = f.read(); // MSB
      return result;
    }

    uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
      return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
    }

    byte decToBcd(byte val){
      // Convert normal decimal numbers to binary coded decimal
      return ( (val/10*16) + (val%10) );
    }
    
void reset_tfts(int reset_pin){
  pinMode(reset_pin, OUTPUT);
  digitalWrite(reset_pin, LOW);
  delay(100);
  digitalWrite(reset_pin, HIGH);
  delay(100);
}

If I use the example code by Tom I (see following code), the pushbutton works as expected.
Code:
/*
  Button
 
 Turns on and off a light emitting diode(LED) connected to digital  
 pin 13, when pressing a pushbutton attached to pin 2. 
 
 
 The circuit:
 * pushbutton attached to pin 16 from ground
 * 10K resistor attached to pin 16 from +5V (pullup)
 
 created 2005
 by DojoDave <http://www.0j0.org>
 modified 30 Aug 2011
 by Tom Igoe
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Button
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 16;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
  // Pin 13: Arduino has an LED connected on pin 13
  // Pin 11: Teensy 2.0 has the LED on pin 11
  // Pin  6: Teensy++ 2.0 has the LED on pin 6
  // Pin 13: Teensy 3.0 has the LED on pin 13

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop(){
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {     
    // turn LED on:    
    digitalWrite(ledPin, HIGH);  
  } 
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
  }
}

Is digitalRead somehow influenced by SPI?

Thank you,
Dani
 
You must use pinMode(16, INPUT) or pinMode(16, INPUT_PULLUP) to put the pin into input mode.

On Teensy 3.1, by default the pins start in a special power-saving disabled mode. This has a benefit of preventing the pin from consuming extra power, but it also means you must configure the pin before you can use it.
 
Status
Not open for further replies.
Back
Top