chipKIT® Development Platform

Inspired by Arduino™

ChipKit Wifi Shield Max32 writing to SD in between UDP socke

Created Mon, 11 Mar 2013 05:28:21 +0000 by doug_c_cameron


doug_c_cameron

Mon, 11 Mar 2013 05:28:21 +0000

HI,

I am so confused. How do i write to the uSD on the Chipkit Wifi shield in between udp reads and writes. I have the latest libraries, the latest MPIDE. I can send UDP packets when i am not using the SD. I can write to the SD when i am not using the WIFI, but i cannot use both at the same time.

The result is that the program locks up and stops running after it makes a DNETcK function call after writing to the SD card.

Is there an example of someone making something like this work on their board?

Thank you so much, because i am trying to record GPS data and send it to another device for plotting as high a rate as possible.

THank you.

#include <WString.h>
#include <TinyGPS.h>
#include <WiFiShieldOrPmodWiFi.h>
#include <SD.h>
#include <stdlib.h>
#include <DNETcK.h>
#include <DWIFIcK.h>
IPv4 ipServer = {10,0,1,8};
unsigned short portServer = DNETcK::iPersonalPorts44 + 400; 
const char * szSsid = "SuperFast";
#define USE_WPA2_PASSPHRASE
const char * szPassPhrase = "1231231231";
#define WiFiConnectMacro() DWIFIcK::connect(szSsid, szPassPhrase, &status)
typedef enum
{
 NONE = 0,
 INITIALIZE,
 LISTEN,
 ISLISTENING,
 AVAILABLECLIENT,
 ACCEPTCLIENT,
 READ,
 WRITE,
 CLOSE,
 EXIT,
 DONE
} STATE;

STATE state = INITIALIZE;


unsigned tStart = 0;
unsigned tWait = 5000;
byte rgbUDPClientCache[1024];
UdpClient udpClient(rgbUDPClientCache, sizeof(rgbUDPClientCache));
const int cPending = 3; // number of clients the server will hold until accepted
byte rgbUDPServerCache[cPending * sizeof(rgbUDPClientCache)];
UdpServer udpServer(rgbUDPServerCache, sizeof(rgbUDPServerCache), cPending);
byte rgbRead[1024];
int cbRead = 0;
int count = 0;
DNETcK::STATUS status;


TinyGPS gps;
int CS = 4;
int LED = 13;



//Define String
String SD_date_time = "invalid";
String SD_lat = "invalid";
String SD_long = "invalid";
String SD_String = "";
char Sout[1000];
char Lat[20];
char Lon[20];

static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec, int SD_val);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);

void setup()
{

 pinMode(10, OUTPUT); // Chip Select Pin for the WIFI Card
 digitalWrite(10,LOW);
 pinMode(CS, OUTPUT); // Chip Select Pin for the SD Card
 pinMode(LED, OUTPUT); // LED Indicator


// Serial Interfaces
 Serial.begin(115200);
 Serial1.begin(9600);



//Connect to the SD Card
if(!SD.begin(CS))
 {
 Serial.println("Card Failure");
 return;
 }
 Serial.print("Status = ");
 Serial.println(status,DEC);



 Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
 Serial.println();
 Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
 Serial.println();
 Serial.println("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum");
 Serial.println(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail");
 Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");



 DNETcK::STATUS status;
 int conID = DWIFIcK::INVALID_CONNECTION_ID;
 
// Serial.begin(9600);
 Serial.println("WiFiUDPEchoServer 1.0");
 Serial.println("Digilent, Copyright 2012");
 Serial.println("");

 if((conID = WiFiConnectMacro()) != DWIFIcK::INVALID_CONNECTION_ID)
 {
 Serial.print("Connection Created, ConID = ");
 Serial.println(conID, DEC);
 state = INITIALIZE;
 }
 else
 {
 Serial.print("Unable to connection, status: ");
 Serial.println(status, DEC);
 state = CLOSE;
 }

 // intialize the stack with a static IP
 DNETcK::begin(ipServer);
 Serial.print("Status = ");
 Serial.println(status,DEC);



}

void loop()
{
 bool newdata = false;
 unsigned long start;

 Serial.print("State = ");
 Serial.println(state);
 Serial.print("Status = ");
 Serial.println(status,DEC);

 switch(state)
 {

 // say to listen on the port
 case INITIALIZE:
 Serial.println("initialize");
 Serial.println("initialize");
 // Serial.println(status);
 // Serial.println(&status);
 Serial.println("statusized");
 if(DNETcK::isInitialized(&status))
 {
 Serial.println("IP Stack Initialized");
 state = LISTEN;
 }
 else if(DNETcK::isStatusAnError(status))
 {
 Serial.print("Error in initializing, status: ");
 Serial.println(status, DEC);
 state = EXIT;
 }
 Serial.println("end of initialize");
 break;
 case LISTEN:
 if(udpServer.startListening(portServer))
 {
 Serial.println("Started Listening");
 state = ISLISTENING;
 }
 else
 {
 state = EXIT;
 }
 break;

 // not specifically needed, we could go right to AVAILABLECLIENT
 // but this is a nice way to print to the serial monitor that we are 
// actively listening.
 // Remember, this can have non-fatal falures, so check the status
 case ISLISTENING:
 if(udpServer.isListening(&status))
 {
 Serial.print("Listening on port: ");
 Serial.print(portServer, DEC);
 Serial.println("");
 state = AVAILABLECLIENT;
 }
 else if(DNETcK::isStatusAnError(status))
 {
 state = EXIT;
 }
 break;

 // wait for a connection
 case AVAILABLECLIENT:
 if((count = udpServer.availableClients()) > 0)
 {
 Serial.print("Got ");
 Serial.print(count, DEC);
 Serial.println(" clients pending");
 state = ACCEPTCLIENT;
 }
 break;

 // accept the connection
 case ACCEPTCLIENT:

 // probably unneeded, but just to make sure we have
 // udpClient in the "just constructed" state
 udpClient.close(); 

// accept the client 
if(udpServer.acceptClient(&udpClient))
 {
 Serial.println("Got a Connection");
 state = WRITE;
 tStart = (unsigned) millis();
 }

 // this probably won't happen unless the connection is dropped
 // if it is, just release our socket and go back to listening
 else
 {
 state = CLOSE;
 }
 break;



 case WRITE:
 Serial.println("WRITE");

 Serial.println("Writing datagram: "); 
for(int i=0; i < cbRead; i++) 
{
 Serial.print(rgbRead[i], BYTE);
 }
 Serial.println(""); 

udpClient.writeDatagram(rgbRead, cbRead);
 state = WRITE;
 tStart = (unsigned) millis();
 break;

 // close our udpClient and go back to listening
 case CLOSE:
 udpClient.close();
 Serial.println("Closing UdpClient");
 Serial.println("");
 state = WRITE;
 break;

 // something bad happen, just exit out of the program
 case EXIT:
 udpClient.close();
 udpServer.close();
 Serial.println("Something went wrong, sketch is done."); 
state = DONE;
 break;

 // do nothing in the loop
 case DONE:
 default:
 break;
 }
 Serial.print("Status = ");
 Serial.println(status,DEC);


// dataString = "";
 Serial.println("set dataString");

 start = millis();
 // Every second we print an update
 while (millis() - start < 1000)
 {
 // Serial.print(millis()-start);
 if (feedgps())
 {
 newdata = true;
 }
 }
 Serial.print("StatusAfterMillies = ");
 Serial.println(status,DEC);


 // Write the newest information to the SD Card
// dataString = SD_date_time + "," + SD_lat + "," + SD_long; 
// dataString = TinyGPS::_term;
// cbRead = dataString.length();
// rgbRead = dataString;
//cbRead = String::getBytes(dataString,5);
//dataString.getBytes(rgbRead,dataString.length());
 Serial.print("StatusGpsDump = ");
 Serial.println(status,DEC);


 gpsdump(gps);


for (int v =0;v< cbRead;v++)
{
rgbRead[v] = Sout[v];
}

Serial.println("after buffer setup");
Serial.println("before end of loop");

 //if(SD_date_time != "invalid")
 // digitalWrite(LED, HIGH);
 //else
 // digitalWrite(LED, LOW);
/* 
//Open the Data CSV File
 File dataFile = SD.open("LOG.csv", FILE_WRITE);
 if (dataFile)
 {
 dataFile.println(dataString);
 Serial.println(dataString);
 dataFile.close();
 } 
else
 {
 Serial.println("\nCouldn't open the log file!");
 }
*/

// state = WRITE;
 Serial.print("StatusBeforeEnd = ");
 Serial.println(status,DEC);

 // every pass through loop(), keep the stack alive
 DNETcK::periodicTasks(); 
Serial.println("end of loop");
}

static void gpsdump(TinyGPS &gps)
{
 float flat, flon;
 unsigned long age, date, time, chars = 0;
 unsigned short sentences = 0, failed = 0;
 static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

 print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
 print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
 gps.f_get_position(&flat, &flon, &age);
 print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5, 1); // Latitude
 print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5, 2); // Longitude
 print_int(age, TinyGPS::GPS_INVALID_AGE, 5); 

print_date(gps); // Date adn Time

 print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2, 0);
 print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2, 0);
 print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2, 0);
 print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
 print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
 print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2, 0);
 print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);

 gps.stats(&chars, &sentences, &failed);
 print_int(chars, 0xFFFFFFFF, 6);
 print_int(sentences, 0xFFFFFFFF, 10);
 print_int(failed, 0xFFFFFFFF, 9);
 Serial.println();
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
 char sz[32];
 if (val == invalid)
 strcpy(sz, "*******");
 else
 sprintf(sz, "%ld", val);
 sz[len] = 0;
 for (int i=strlen(sz); i<len; ++i)
 sz[i] = ' ';
 if (len > 0) 
sz[len-1] = ' ';
 Serial.print(sz);
 feedgps();
}

static void print_float(float val, float invalid, int len, int prec, int SD_val)
{
 char sz[32];
 if (val == invalid)
 {
 strcpy(sz, "*******");
 sz[len] = 0;
 if (len > 0) 
sz[len-1] = ' ';
 for (int i=7; i<len; ++i)
 sz[i] = ' ';
 Serial.print(sz);
 if (SD_val == 1) SD_lat = sz;
 else if(SD_val == 2) SD_long = sz;
 }
 else
 {
 Serial.print(val, prec);

 if (SD_val == 1) {sprintf(Lat,"%f",val); SD_lat=Lat; }
 else if (SD_val == 2) {sprintf(Lon,"%f",val); SD_long=Lon;}

 int vi = abs((int)val);
 int flen = prec + (val < 0.0 ? 2 : 1);
 flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
 for (int i=flen; i<len; ++i)
 Serial.print(" ");
 }
 feedgps();
}

static void print_date(TinyGPS &gps)
{
 int year;
 byte month, day, hour, minute, second, hundredths;
 unsigned long age;
 gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
 if (age == TinyGPS::GPS_INVALID_AGE)
 {
 Serial.print("******* ******* ");
 SD_date_time = "invalid"; 
}
 else
 {
 char sz[32];
 sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",
 month, day, year, hour, minute, second);
 Serial.print(sz);
 SD_date_time = sz;
 }
 print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
 feedgps();
}

static void print_str(const char *str, int len)
{
 int slen = strlen(str);
 for (int i=0; i<len; ++i)
 Serial.print(i<slen ? str[i] : ' ');
 feedgps();
}

static bool feedgps()
{
 char temp;
// dataString = "";
//Serial.print("feedgps = ");
 static int i = 0;
 while (Serial1.available())
 {
 temp = Serial1.read();
 if (temp == '$')
 {
 cbRead = i-1;
 for (int j=0;j<=cbRead;j++)
 {
 Serial.print(Sout[j]);
 }

 Serial.print("cbRead = ");
 Serial.println(cbRead);

 // SD_String = ""; 
/* for (int k =0;k< cbRead;k++)
 {
 rgbRead[k] = Sout[k];
 // SD_String = SD_String + Sout[k];
 }
 */

 // Serial.println(SD_String);
 // Serial.println("after buffer setup");


 //if(SD_date_time != "invalid")
 // digitalWrite(LED, HIGH);
 //else
 // digitalWrite(LED, LOW);

 digitalWrite(10,HIGH);

 //Open the Data CSV File
 Serial.println("open file");
 File dataFile = SD.open("LOG.csv", FILE_WRITE);
 Serial.print("StatusAfterSDOpen");
 Serial.println(status,DEC);
 Serial.println("tried");
 if (dataFile)
 {
 for (int j=0;j<=cbRead;j++)
 {
 dataFile.print(Sout[j]);
 }

 Serial.println("SD SD SD SD");
 dataFile.close();
 } 
else
 {
 Serial.println("\nCouldn't open the log file!");
 }
 digitalWrite(10,LOW);

 Serial.print("StatusAfterWrite");
 Serial.println(status,DEC);


 i = 0;
 for (int kk=0; kk<1000; kk++)
 {
 Sout[kk] = ' ';
 }
 }

 Sout[i++]=temp;

 if (gps.encode(temp))
 {
 return true;
 }
 }
 return false;
}

PICedh

Thu, 11 Apr 2013 06:54:53 +0000

hello,

I have the same issue, I have enter the topic "SPI conflict MAX32 between WIFI and SD Card" at the same time


KeithV

Mon, 15 Apr 2013 03:47:23 +0000

Yes, this has been a thorn in our side for a long while now. There is no "good" fix but there is a functional fix that works for the WiFiShield. The problem is the WiFi and SD both share the same SPI port, SPI2; and the WiFi module responds to INT1 on the WiFiShield. If you are reading the SD card when the WiFi gets an interrupt, the WiFi will CS the WiFi module and both the SD and WiFi SPI devices will be selected and corruption occurs.

The easy fix is to disable interrupts when you read/write to the SD card so the WiFi INT will not be processed until after the SD read/write is complete, thus serializing the SPI communications.

The problem with this is that the UART will also have its interrupt blocked and if you are also reading data in the UART, once the PIC32 4 byte FIFO is full, you will start to lose data because the UART interrupt routine will not run, and the PIC32 FIFO will overflow.

A better fix is to only disable INT1 while reading/writing the SD card. But then this assumes the WiFi is always on INT1 and INT1 is not used for something else. With the WiFiShield, that is probably a good assumption, but for the Cerebot boards that use PmodWiFis, that is definitely not a good assumption. The code fix I provide below is targeted to boards that would use the WiFiShield.

The real solution is to somehow provide a mechanism for the WiFi library to tell the SD library what interrupt to disable when selecting the SD reader; something we will have to add to MPIDE. This then would allow any interrupt driven device to share the SPI port with the SD card.

Now, depending on what version of MPIDE you have installed you may have:

  1. No fix at all.
  2. All interrupts being disabled/enabled on SD read/write
  3. a plib version that disables/enables INT1 on SD read/write
  4. a plib-free version that disables/enables INT1 (I think this is only in private builds at this time) on SD read/write.

If you are out right failing, you are probably using MPIDE mpide-0023-windows-20120903 or earlier. (maybe 1013 as well, somewhere in that build range). I think 203 has the enable/disable all interrupt fix.

If you go to ....\hardware\pic32\libraries\SD\utility\Sd2Card.cpp and look for the functions Sd2Card::chipSelectHigh(void) and void Sd2Card::chipSelectLow(void), these are the functions you need to replace. Below, I will give both the plib and the plib-free versions. Understand, the plib-free version will not compile unless you have a plib-free MPIDE (for windows that is mpide-0023-windows-20130401-test or newer). Also, understand that none of these solutions are optimal and depend highly on SPI2 being shared and INT1 being used by the WiFi. I have been using this fix for awhile now, and I have not had any bad side-effects... but just beware that INT1 is getting disabled while you are using the SD reader.

Hope this helps

The plib verison...

uint32_t spi_state; uint8_t fspi_state_saved = false;

//------------------------------------------------------------------------------ void Sd2Card::chipSelectHigh(void) { digitalWrite(chipSelectPin_, HIGH); #if defined(BOARD_MEGA) || defined(BOARD_UNO) || defined(BOARD_UC32) if(fspi_state_saved) #endif } //------------------------------------------------------------------------------ void Sd2Card::chipSelectLow(void) #endif digitalWrite(chipSelectPin_, LOW); }

The plib-free version

uint32_t spi_state; uint8_t fspi_state_saved = false; uint32_t interrupt_state = 0;

//------------------------------------------------------------------------------ void Sd2Card::chipSelectHigh(void) { digitalWrite(chipSelectPin_, HIGH); #if defined(BOARD_MEGA) || defined(BOARD_UNO) || defined(BOARD_UC32) if(fspi_state_saved) #endif } //------------------------------------------------------------------------------ void Sd2Card::chipSelectLow(void) #endif digitalWrite(chipSelectPin_, LOW); }


PICedh

Tue, 16 Apr 2013 19:19:43 +0000

Thanks a lot for this detailed explanation !

I have updated the SDCard lib as proposed in order to deactivate INT1 during the Chip select and It works ! I can now stay connected in WIFI and access to the SDCard.

Eric