Problems while using multiple SPI devices - CC3000 and AT45 series Flash

Hello,

I am having problems when trying to communicate with multiple devices on the the SPI bus. We’re using the CC3000 breakout board from Adafruit (new version with the buffer on the MISO line) with a Adesto/Atmel Dataflash chip (AT45 series). We can communicate with the CC3000 and the dataflash in isolation, but when we try to combine the two codes, we run into issues communication with the CC3000 after we’ve setup the dataflash.

We’re using the Adafruit CC3000 library(GitHub - adafruit/Adafruit_CC3000_Library: Library code for Adafruit's CC3000 WiFi breakouts &c), and the arduino dataflash library (GitHub - BlockoS/arduino-dataflash: Support for Atmel Dataflash for the Arduino)

On further investigation it seems that the communication with CC3000 breaks as soon as I run the dataflash setup routine. After this point I can communicate with the flash but not the CC3000.

Important considerations:
1 - Dataflash works on SPI mode 3 while CC3000 works on SPI mode 1.
2 - I’m using a bootloaded 1284p, that’s why the pin configuration is not the same as the one used for the actual uno board.
3 - I tried to download Arduino 1.5.8, which is supposed to support SPI transactions, but manic bug bootloader does not work on it yet.

I’ve attached the complete code below (only excluded the definitions of some wifi functions that does not matter). The program hangs in part 2 (indicated as comment in the end of the code).

#include <Arduino.h>
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include "DataFlash.h"
#include <string.h>
#include "utility/debug.h"

#define NUM_PAGES 5

// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   11  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  3
#define ADAFRUIT_CC3000_CS    4
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed but DI

#define WLAN_SSID       "xxxxx"        // cannot be longer than 32 characters!
#define WLAN_PASS       "yyyyy"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_UNSEC

DataFlash dataflash;

uint16_t page;
uint8_t data; 
int k = 0;
int flagReady = 0;
  

/**************************************************************************/
/*!
    @brief  Sets up the HW and the CC3000 module (called automatically
            on startup)
*/
/**************************************************************************/
void setup(void)
{   
  page = 0 ;
  SPI.begin();  
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n"));

  displayDriverMode();
  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
 
  /* Initialise the module */
  Serial.println(F("\nInitialising the CC3000 ..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
    while(1);
  }

  displayMACAddress();
 
  /* Optional: Get the SSID list (not available in 'tiny' mode) */
#ifndef CC3000_TINY_DRIVER
  listSSIDResults();
#endif
 
  /* Delete any old connection data on the module */
  Serial.println(F("\nDeleting old connection profiles"));
  if (!cc3000.deleteProfiles()) {
    Serial.println(F("Failed!"));
    while(1);
  }

  /* Attempt to connect to an access point */
  char *ssid = WLAN_SSID;             /* Max 32 chars */
  Serial.print(F("\nAttempting to connect to ")); Serial.println(ssid);
 
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }
   
  Serial.println(F("Connected!"));
}

void loop(void)
{   
    char eMessage1[] = "@ The device was disconnected ";
    
    if(!cc3000.checkConnected())
    {
      if(k==0)
      {
        float time = millis();
        time=(time/1000);
        Serial.println(F("\nThe device is disconnected"));
        Serial.print(F("Disconnetion time: "));
        Serial.print(time);
        ++k;
        delay(1000);
      } 
      //Initialization and usage of the flash:
      delay(1000);
      dataflash.setup(0,1,2);   //Set pins for CS, RESET and WP, respectively
      delay(10);
      dataflash.begin();

      dataflash.bufferWrite(1, 0); //Stores whatever is being transmitted in SPI bus in BUFFER 1       
      for(unsigned int i=0; eMessage1[i] != '\0'; ++i)
      {
        SPI.transfer(eMessage1[i]); //eMessage1 is transferred to bus 1.
      }
      SPI.transfer('\0');  
      dataflash.bufferToPage(1,page); //transfers content of buffer 1 to page 0.
      ++page;          
      if(page >= NUM_PAGES -3) //you only get here if you've written at least 2 pages
      {
        for(unsigned int j=0; j<NUM_PAGES-3; ++j)
        {
          dataflash.pageRead(page,0);
          unsigned int z = 0;
          Serial.println(F("\nContent stored in the FLASH: "));
          do
          {
            data = SPI.transfer(0xff);
            if(data != '\0')
            Serial.print(data);
            Serial.print(" ");
          }  while((data != '\0') && (j < 64));
          delay(500);
        }
        flagReady = 1;
        page = 0;
      }
    }   
    
    //PART 2: Where we have the re-connection problem
    if(flagReady == 1)
    {
      Serial.println(F("\nRe-Initializing the CC3000..."));
      delay(500);
      if (cc3000.begin())
      Serial.println("\nRe-initialized"); 
      if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY))
      {     //It gets stuck here. As if the program couldn't understand this after I used the Flash.
        delay(1000);         
        Serial.println(F("\nFailed to reconnect!"));
        while(1);
      }
      else
      {
       Serial.println("\nSuccedded to reconnect");
      }
     Serial.println("test");
    }
}

You are facing a few challenges using those devices together.

One, they use different SPI modes, so you must change to mode 3 when using the Dataflash chip, then change back to mode 0.

Two, you must set the DataFlash slave select LOW before using the Dataflash, then set it High again after using it.

Three, it appears the CC3000 uses the SPI bus in its interrupt, so you must disable interrupts when using the Dataflash.

   cli; // stop CC3000 interrupts
   SPI.setDataMode(SPI_MODE3);
   digitalWrite(DataFlashSS, LOW);

   // do your DataFlash comm here, then...

   digitalWrite(DataFlashSS,HIGH);
   SPI.setDataMode(SPI_MODE0);
   sei; // start CC3000 interrupts

Whew! I hope I covered everything.

The IDE v1.5.8 is supposed to allow SPI devices that use interrupts to coexist with other SPI devices that don't, but I have not tested that yet.

Most third party libraries do not have the required functions installed to use the SPI interrupts in IDE v1.5.8.

SurferTim:
You are facing a few challenges using those devices together.

One, they use different SPI modes, so you must change to mode 3 when using the Dataflash chip, then change back to mode 0.

Two, you must set the DataFlash slave select LOW before using the Dataflash, then set it High again after using it.

Three, it appears the CC3000 uses the SPI bus in its interrupt, so you must disable interrupts when using the Dataflash.

Hi SurferTim! First of all, thanks for your reply!
I did the changes as you suggested, but the program gets stuck after the cli() call.

By the way, I didn't make this clear, but I'm able to connect to the WiFi, poll to see if the connection was lost (in case someone disconnects the device), in case it is, I write an error message to the flash. This first part runs ok; however, when I try to re-establish the connection with the Wifi (Part 2 indicated in the code), the processor fails to communicate a second time to the WiFi. Note that the problem happens after I was able to communicate to both devices a first time.

Where did you get the dataflash library?

SurferTim:
Where did you get the dataflash library?

Here's the link: GitHub - BlockoS/arduino-dataflash: Support for Atmel Dataflash for the Arduino

Your call to dataflash.pageRead(page,0) is probably causing you problems. That function leaves the dataflash slave select LOW (active).

     if(page >= NUM_PAGES -3) //you only get here if you've written at least 2 pages
      {
        for(unsigned int j=0; j<NUM_PAGES-3; ++j)
        {

// this may cause you the problem
          dataflash.pageRead(page,0);


          unsigned int z = 0;
          Serial.println(F("\nContent stored in the FLASH: "));
          do
          {
            data = SPI.transfer(0xff);
            if(data != '\0')
            Serial.print(data);
            Serial.print(" ");
          }  while((data != '\0') && (j < 64));
          delay(500);
        }
        flagReady = 1;
        page = 0;
      }
    }   

// when you get here, the dataflash slave select is still LOW (active)    
    //PART 2: Where we have the re-connection problem
    if(flagReady == 1)

This is from the library code

/**

  • A main memory page read allows the user to read data directly from
  • any one of the pages in the main memory, bypassing both of the
  • data buffers and leaving the contents of the buffers unchanged.
  • Reading past the end of the page wraps around to the beginning of
  • the page.
  • The chip must remain enabled by this function; it is the user’s
    * responsibility to disable the chip when finished reading.
  • @param page Page of the main memory to read.
  • @param offset Starting byte address within the page (default value: 0).
    **/
void DataFlash::pageRead(uint16_t page, uint16_t offset)
{
    reEnable();     // Reset command decoder.
    
    /* Send opcode */
    SPI.transfer(DATAFLASH_PAGE_READ);
    
    /* Address (page | offset)  */
    SPI.transfer(pageToHiU8(page));
    SPI.transfer(pageToLoU8(page) | (uint8_t)(offset >> 8));
    SPI.transfer((uint8_t)(offset & 0xff));
    
    /* 4 "don't care" bytes */
    SPI.transfer(0);
    SPI.transfer(0);
    SPI.transfer(0);
    SPI.transfer(0);
    
    // Can't disable the chip here!
}

Note the "Can’t disable the chip here message?

I've tried to set Flash_CS to high after talking to the flash, but it made no difference :frowning:
I'm thinking of implementing software SPI (bit banging) to talk to the flash and leave the hardware SPI for the CC3000.

This is your dataflash setup call. Is your CS pin D0? Is your reset pin D1? those are the serial I/O pins.

      dataflash.setup(0,1,2);   //Set pins for CS, RESET and WP, respectively

matheusmestres:
I've tried to set Flash_CS to high after talking to the flash, but it made no difference :frowning:

I don't see that variable defined anywhere.

matheusmestres:
I'm thinking of implementing software SPI (bit banging) to talk to the flash and leave the hardware SPI for the CC3000.

I don't know about that. I haven't used the hardware and software SPI together.

This is your dataflash setup call. Is your CS pin D0? Is your reset pin D1? those are the serial I/O pins.
dataflash.setup(0,1,2);  //Set pins for CS, RESET and WP, respectively

I'm using a bootloaded ATMega 1284p (44pins). Pins 0 and 1 are regular I/O pins.

I've tried to set Flash_CS to high after talking to the flash, but it made no difference :frowning:

I don't see that variable defined anywhere.

I've tried this after your suggestion. Just declared int Flash_CS = 0 and set it to HIGH after talking to the flash.

I'm thinking of implementing software SPI (bit banging) to talk to the flash and leave the hardware SPI for the CC3000.

I don't know about that. I haven't used the hardware and software SPI together.

I'm confused, should it be a problem to use both of them at the same time? Since they're using different pins, there shouldn't be any problem, right?