How to use Octows2811 and SPI ?

Status
Not open for further replies.

Yannick

Active member
Hello all,

I try to use an optical flow sensor to drive a strip led from a teensy 3.6 .

- I can read the sensor which is spi connected (pins used : 9, 10, 11, 12, 13)
- I can command the leds using octows2811 library.

I cannot do both, as soon as I use "led.show" it blocks...:(

Any idea?

Thank's , y.

The code :
Code:
/* Copyright (C) 2015 Kristian Sloth Lauszus. All rights reserved. Send data from ADNS3080 as raw bytes. Based on the code by Randy Mackay. DIYDrones.com
   Kristian Sloth Lauszus ----  http://www.lauszus.com -----  lauszus@gmail.com
   
   https://www.pjrc.com/teensy/td_libs_SPI.html
   
*/
// *********************    octo   *******************
#include <OctoWS2811.h>

#define RED    0x010000
#define GREEN  0x000100
#define BLUE   0x000001
#define YELLOW 0x010100
#define PINK   0x010001
#define ORANGE 0x000101
#define WHITE  0x010101

const int ledsPerStrip = 60;

DMAMEM int displayMemory[ledsPerStrip*6];
int drawingMemory[ledsPerStrip*6];

const int config = WS2811_GRB | WS2811_800kHz;

OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);

//  *********************  3080  *********************
#include <SPI.h>

SPISettings spiSettings(2e6, MSBFIRST, SPI_MODE3); // 2 MHz, mode 3

// Register Map for the ADNS3080 Optical OpticalFlow Sensor
#define ADNS3080_PRODUCT_ID            0x00
#define ADNS3080_MOTION                0x02
#define ADNS3080_DELTA_X               0x03
#define ADNS3080_DELTA_Y               0x04
#define ADNS3080_SQUAL                 0x05
#define ADNS3080_CONFIGURATION_BITS    0x0A
#define ADNS3080_Extended_Config       0x0B
#define ADNS3080_MOTION_CLEAR          0x12
#define ADNS3080_FRAME_CAPTURE         0x13
#define ADNS3080_MOTION_BURST          0x50

// ADNS3080 hardware config
#define ADNS3080_PIXELS_X              30
#define ADNS3080_PIXELS_Y              30

// Id returned by ADNS3080_PRODUCT_ID register
#define ADNS3080_PRODUCT_ID_VALUE      0x17

// pour teensy 3.6   voir https://www.pjrc.com/teensy/td_libs_SPI.html 
// these pins may be different on different boards
static const uint8_t RESET_PIN = 9;
// #define PIN_SCK  13
// #define PIN_MISO 12
// #define PIN_MOSI 11
static const uint8_t SS_PIN = SS; // Pin 10   #define PIN_SS 10

static int32_t x, y;
static float d ;
char art[] = "WX86*3I>!;~:,`. ";  // 




void setup() 
{
  Serial.begin(115200) ;    while (!Serial); // Wait for serial port to open
  
//  *****************   octo  *********************
    leds.begin(      ) ;
    leds.show (      ) ;
	for (int i = 0 ; i<610 ; i++) { leds.setPixel(60*6+i%60, 0x010000 );    leds.show();    leds.setPixel(60*6+i%60, 0x000000 ); delay(5); } ;
//  **********************   3080   ****************
  SPI.begin();

  // Set SS and reset pin as output
  pinMode(SS_PIN, OUTPUT);
  pinMode(RESET_PIN, OUTPUT);
  reset();

  uint8_t id = spiRead(ADNS3080_PRODUCT_ID);
  if (id == ADNS3080_PRODUCT_ID_VALUE)    Serial.println(F("ADNS-3080 found yj"));  else {    Serial.print(F("Could not find ADNS-3080: "));    Serial.println(id, HEX);    while (1);  }

  //  uint8_t config = spiRead(ADNS3080_CONFIGURATION_BITS);   spiWrite(ADNS3080_CONFIGURATION_BITS, config | 0x10); // Set resolution to 1600 counts per inch  400 par default

  
  while (spiRead(ADNS3080_Extended_Config) & 0x80) ;   // attendre qu il soit  possible d ecrire 
spiWrite(0x19, 0xe0); // 2000Hz
spiWrite(0x1a, 0x2e); // 2000Hz
  delay(10);
  
  Serial.println(F("  Setup done ")); 
}





void loop() 
{
#if 1
  updateSensor();   delayMicroseconds(30000);    colorWipe(RED); 

#else
  Serial.write("start\n");  printPixelData();  Serial.flush();  delay(50);
#endif
}



 char str[32] ;

void updateSensor(void) {
  // Read sensor
  uint8_t buf[7];    spiRead(ADNS3080_MOTION_BURST, buf, 7);     uint8_t motion = buf[0];                                 

  if (motion & 0x10) Serial.println(F("ADNS-3080 overflow\n"));      // Check if we've had an overflow
  else if (motion & 0x80) 
//  else 
       {
         int8_t dx = buf[1];    int8_t dy = buf[2];    uint8_t surfaceQuality = buf[3];   d += (float) sqrt( sq((float)dx) + sq((float)dy) ) ;      //   x += dx;    y += dy; 
	     sprintf(str, "%2x %05i,%4i  %5i,%4i  %3i %3i %3i %3i", motion, x, dx, y, dy, surfaceQuality, buf[4], buf[5], buf[6]); Serial.println(str);  Serial.println(d);      Serial.flush();
       }
//     else      Serial.println(motion, HEX);
//  delay(10);
}


void colorWipe(int color)   
{  int i=6*60 + (int)d % 60 ;    
leds.setPixel(i, color);    
//leds.show();    
leds.setPixel(i, 0 );
}










void reset(void) {  digitalWrite(RESET_PIN, HIGH);   delayMicroseconds(10);  digitalWrite(RESET_PIN, LOW);   delayMicroseconds(500); }

// Will cause the Delta_X, Delta_Y, and internal motion registers to be cleared
void clearMotion() {  spiWrite(ADNS3080_MOTION_CLEAR, 0xFF);   x = y = 0; } // Writing anything to this register will clear the sensor's motion registers

void spiWrite(uint8_t reg, uint8_t data) {  spiWrite(reg, &data, 1); }

void spiWrite(uint8_t reg, uint8_t *data, uint8_t length) {
  SPI.beginTransaction(spiSettings);
  digitalWrite(SS_PIN, LOW);

  SPI.transfer(reg | 0x80); // Indicate write operation
  delayMicroseconds(75); // Wait minimum 75 us in case writing to Motion or Motion_Burst registers
  SPI.transfer(data, length); // Write data

  digitalWrite(SS_PIN, HIGH);
  SPI.endTransaction();
}


uint8_t spiRead(uint8_t reg) {  uint8_t buf;  spiRead(reg, &buf, 1);  return buf;}


void spiRead(uint8_t reg, uint8_t *data, uint8_t length) 
{
  SPI.beginTransaction(spiSettings);
  digitalWrite(SS_PIN, LOW);

  SPI.transfer(reg); // Send register address
  delayMicroseconds(75); // Wait minimum 75 us in case writing to Motion or Motion_Burst registers
  memset(data, 0, length); // Make sure data buffer is 0
  SPI.transfer(data, length); // Write data

  digitalWrite(SS_PIN, HIGH);
  SPI.endTransaction();
}






void printPixelData(void) 
{
  bool isFirstPixel = true;                                         //char str[16];
  
  spiWrite(ADNS3080_FRAME_CAPTURE, 0x83);        // Write to frame capture register to force capture of frame

  delayMicroseconds(1510);                         //Wait 3 frame periods + 10 micro-seconds for frame to be captured      Minimum frame speed is 2000 frames/second so 1 frame = 500 µ seconds. So 500 x 3 + 10 = 1510

  for (uint8_t i = 0; i < ADNS3080_PIXELS_Y; i++)                    // Display the pixel data
  {
    for (uint8_t j = 0; j < ADNS3080_PIXELS_X; j++) 
	{
      uint8_t regValue = spiRead(ADNS3080_FRAME_CAPTURE);
      if (isFirstPixel && !(regValue & 0x40)) {        Serial.println(F("Failed to find first pixel"));        goto reset;      }
      isFirstPixel = false;
//    uint8_t pixelValue = regValue << 2; // Only lower 6 bits have data
      uint8_t pixelValue = (regValue & 0x3f)+32 ; // ((regValue & 0x3f)<<2) >> 4; // Only lower 6 bits have data    
//    Serial.write(    pixelValue    );
//    Serial.write((char)pixelValue);  Serial.print(' '); //Serial.write(art[pixelValue]);  Serial.print(' ');  //  
//    sprintf(str, "%2i"  , (int)  pixelValue-32     );   Serial.print(str);  //Serial.write(art[pixelValue]);  Serial.print(' ');  //  
      Serial.write(    pixelValue-32    ); 
    }
//    Serial.println(); // yj
	Serial.flush();
  }

reset:
  reset(); // Hardware reset to restore sensor to normal operation
}
 
Is this the code you're using to observe whether OctoWS2811 is working?

Code:
void colorWipe(int color)
{ 
  int i = 6 * 60 + (int)d % 60 ;
  leds.setPixel(i, color);
  //leds.show();
  leds.setPixel(i, 0 );
}

Maybe this would be better (for testing purpose) if it didn't depend on "d" which your sensor controls? How will you know whether the problem is hardware, or simply two parts of your program interacting in unexpected ways?

Please test with something like this, which always & reliably does the same observable LED pattern, regardless of your other code.

Code:
void colorWipe(int color)
{
  static unsigned int offset=0;
  int i = 6 * 60 + offset % 60 ;
  offset++;
  leds.setPixel(i, color);
  //leds.show();
  leds.setPixel(i, 0 );
}
 
Thank's Paul,

I found my bug which broke teensy's work only when I uncommented "leds.show();"

A silly mistake of the beginner that I am still and always will be... I thought that I was going to mad...

As says an old french, "I was looking for Noon at 2PM" and forgot that the str[32] in which I printed results , was too short...

Sorry for the "anxiogenic title" of that thread...

y.
 
Hi, I'm also planning to use the OctoWS2811 library with a separate SPI device attached. My device simply needs MOSI and SCK, and doesn't require the MISO or a CS line. There is no return data.

The standard Teensy 3.2 SPI pins are:
SCK 13 (alternate 14)
MOSI 11 (alternate 7)
MISO 12 (alternate 8)

The OoctoWS2811 library reserves a lot of the Teensy 3.2 pins, however MOSI pin 11 is free, SCK pin 13 is free, but MISO pin 12 is reserved by OctoWS2811 for the Video Sync line (which I'm not using). The alternate MISO pin is 8, which is also used by OctoWS2811.

My question is - can I still use the SPI library, but just loose the functionality of MISO ? Will there be any clash between the use of MISO between the OctoWS2811 and SPI library?

If I can't use the SPI with OctoWS2811 on a Teensy 3.2, I shall just move up to a Teensy 3.5 and use the other alternate SPI pins.

Also.... this is my first use of Arduino SPI. I assume if I'm not using a Chip Select, I do not need need to allocate a pin to it, as the CS line seems to be just user code driven at the beginning and end of each transaction, and not used by the SPI library?

Thanks. David.
 
Hi "Ausplex",

To the question : "Will there be any clash between the use of MISO between the OctoWS2811 and SPI library?", I am only able to answer that the code submitted in my own question (on 2018 01 16? 8H36) runs on a Teensy 3.6 , if you replace "char str[32] ;" by "char str[128] ;"...

There were no clash using the OctoWS2811 and SPI library, the way I did on a Teensy 3.6.

To the other part of your question : "can I still use the SPI library, but just loose the functionality of MISO ?" I would simply try to use separatly the SPI library, as you plan ("loose the functionality of MISO"), and the OctoWS2811 library.

I have not in mind the Teensy 3.2 pins, but if there is no overlap between pins used by the OctoWS2811 and the SPI pins, then it should work...

Yannick.
 
Pin 12 is only used by the videodisplay example. It's not used internally by the library, so you can use all the SPI pins.

OctoWS2811 even has a VideoSDcard example which has been used on Teensy 3.2, so you can see SPI definitely can be used together with OctoWS2811. Just don't use pinMode on pin 12 in your program.
 
Status
Not open for further replies.
Back
Top