Go Down

Topic: Feather m0 WiFi - WiFi conflicts with timer based interrupt (Read 36 times) previous topic - next topic

dashk

Hi, I've been struggling with reliably sending data to a client using the WiFi101 library. I want to end up putting my WiFi communication code within the handler function along with other things, but it always crashes after a while. So, I backtracked to see where the problem first starts, and it seems like even just configuring the TC5 timer interrupt breaks it even if the timer isn't being used and the WiFi logic is in loop(). I have also tried using TC3 and TC4, but I fear my knowledge of Arduino interrupts in general is lacking so that didn't help me deduce the problem.

Here is some stripped-down code that clearly exhibits the problem.

Code: [Select]
#include <SPI.h>
#include <WiFi101.h>
#include <Time.h>
#include <time.h>

// WiFi variables
char ssid[] = SECRET_SSID;    // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
WiFiServer server(SERVER_PORT);

#define SAMPLE_FREQUENCY 100

/******************** Main Logic Functions *********************/

void setup() {

  /* Setup WiFi module and server*/

  // Configure pins for Adafruit ATWINC1500 Feather
  WiFi.setPins(8,7,4,2);

  // Initialize serial:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // Check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // Attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // Wait 10 seconds for connection:
    delay(10000);
  }

  // Wifi should be connected
  Serial.println("Connected to wifi");
  print_wifi_status();
  if ( status != WL_CONNECTED) {
    Serial.println("Couldn't get a wifi connection");
    while(true);
  }
  else {
    server.begin();
    Serial.print("Connected to wifi. My address:");
    IPAddress myAddress = WiFi.localIP();
    Serial.println(myAddress);
  }
  Serial.println("Listening for connections");

  // Configure and enable timer interrupt
  tc_configure(SAMPLE_FREQUENCY); //configure the timer to run at <sampleRate>Hertz // CAUSES WIFI FAILURE
//  tc_start_counter(); // don't need to start counter for bug to happen
}

void loop() { 
  send_to_client();
}

void send_to_client() {
  // Poll any available clients
  WiFiClient client = server.available();

  // Check if there is a client connected
  if (client) {

    if (client.connected()) {     
      client.println("a");
    }
   
    client.stop();
    delay(1);
  }
}

void print_wifi_status() {
  // Print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

//Configures the TC to generate output events at the sample frequency.
//Configures the TC in Frequency Generation mode, with an event output once
//each time the audio sample frequency period expires.
void tc_configure(int sampleRate) {
  // Enable GCLK for TCC2 and TC5 (timer counter input clock)
  GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ;
  while (GCLK->STATUS.bit.SYNCBUSY);

  tc_reset(); //reset TC5

  // Set Timer counter Mode to 16 bits
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
  // Set TC5 mode as match frequency
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
  //set prescaler and enable TC5
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
  //set TC5 timer counter based off of the system clock and the user defined sample rate or waveform
  TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / sampleRate - 1);
  while (tc_is_syncing());

  // Configure interrupt request
  NVIC_DisableIRQ(TC5_IRQn);
  NVIC_ClearPendingIRQ(TC5_IRQn);
  NVIC_SetPriority(TC5_IRQn, 0);
  NVIC_EnableIRQ(TC5_IRQn);

  // Enable the TC5 interrupt request
  TC5->COUNT16.INTENSET.bit.MC0 = 1; // CAUSES WIFI FAILURE
  while (tc_is_syncing()); //wait until TC5 is done syncing
}

//Function that is used to check if TC5 is done syncing
//returns true when it is done syncing
bool tc_is_syncing() {
  return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}

//This function enables TC5 and waits for it to be ready
void tc_start_counter() {
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
  while (tc_is_syncing()); //wait until snyc'd
}

//Reset TC5
void tc_reset() {
  TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
  while (tc_is_syncing());
  while (TC5->COUNT16.CTRLA.bit.SWRST);
}

//disable TC5
void tc_disable() {
  TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
  while (tc_is_syncing());
}

/*  TC5_Handler
 * 
 *  INPUT:  none
 *  OUTPUT: none
 *  RETURN: none
 *  DESCRIPTION: Method override for handling the TC5 timer interrupt
 *                 
 */
void TC5_Handler() { // What I want to eventually have

  // Send data
  send_to_client();   

  // END OF YOUR CODE
  TC5->COUNT16.INTFLAG.bit.MC0 = 1; //don't change this, it's part of the timer code
}



I have attached an image of my "output". It works for a little while, then I start timing out when the bug happens, and finally I get completely locked out. There is the additional unexpected behavior of the serial monitor becoming unresponsive when the bug occurs if that provides any additional context.

Any advice would be greatly appreciated! Thanks!

Go Up