I have built a board with a Teensy 3.2, an Adafruit Ethernet Featherwing, and a connector for external connection of SPI lines. Those lines are hooked up with short twisted-pair wires from a Cat5 cable to an MCP3204 evaluation board. Here is the relevant part of my schematic: View attachment 10091
The A/D converter access is working fine as long as I don't try using the Ethernet module. And the Ethernet module works fine when I run it without trying to access the A/D converter. But if I have started listening for UDP packets (rpt.startUDP(mac, ip, localPort);), processing does not proceed past my first attempt to access the SPI bus for the A/D converter transaction.
Below is the pertinent code from my header and CPP files.
Should I expect to be able to make this work? I might be able to live with only enabling Ethernet after doing my A/D converter sampling to report the results and then disabling it to resume sampling, but that would be a pain. I've been looking into Bill Greiman's DigitalIO bit-banging SPI code to just put the A/D converter SPI on its own pins, and might proceed to try to deal with its current crop of compiler errors (templates! inlines! #defines galore!) if that winds up being the best approach. The MCP3204 only supports an SPI clock of 2MHz, so bit-banging with a 72 MHz CPU actually doesn't seem too impractical. But if there is an easy fix for my code as-is, I'd obviously rather stick with it and the hardware SPI.
Thanks for any assistance! The Teensy is a great little product.
Best regards,
Ed Suominen
The A/D converter access is working fine as long as I don't try using the Ethernet module. And the Ethernet module works fine when I run it without trying to access the A/D converter. But if I have started listening for UDP packets (rpt.startUDP(mac, ip, localPort);), processing does not proceed past my first attempt to access the SPI bus for the A/D converter transaction.
Below is the pertinent code from my header and CPP files.
Should I expect to be able to make this work? I might be able to live with only enabling Ethernet after doing my A/D converter sampling to report the results and then disabling it to resume sampling, but that would be a pain. I've been looking into Bill Greiman's DigitalIO bit-banging SPI code to just put the A/D converter SPI on its own pins, and might proceed to try to deal with its current crop of compiler errors (templates! inlines! #defines galore!) if that winds up being the best approach. The MCP3204 only supports an SPI clock of 2MHz, so bit-banging with a 72 MHz CPU actually doesn't seem too impractical. But if there is an easy fix for my code as-is, I'd obviously rather stick with it and the hardware SPI.
Thanks for any assistance! The Teensy is a great little product.
Best regards,
Ed Suominen
Code:
#include <IPAddress.h>
#include <EthernetUdp.h>
#include <Ethernet.h>
#include <SPI.h>
class ADC {
public:
ADC(uint8_t csPin, SPISettings &);
void setVoltageChannel(uint8_t ch);
uint16_t readChannel(uint8_t ch);
void getVI(VoltageCurrent &);
private:
uint8_t csPin;
uint8_t ch_V = 0;
const uint8_t ch_I = 1; // In real system, it will be 2
SPISettings settings;
};
class Reporter {
public:
Reporter(uint8_t csPin, uint8_t resetPin);
void startUDP(byte mac[], IPAddress &, uint16_t localPort);
int checkForPacket();
void stopUDP();
private:
EthernetUDP udp;
};
// Provides SPI access to a Microchip MCP3204 A/D converter
//------------------------------------------------------------------------
ADC::ADC(uint8_t csPin, SPISettings & settings)
{
// Constructs with the CS pin and SPI settings
this->csPin = csPin;
pinMode(csPin, OUTPUT);
digitalWrite(csPin, HIGH);
this->settings = settings;
}
void ADC::setVoltageChannel(uint8_t ch)
{
// Sets the voltage channel to either 0 or 1.
//
// Channel 0 is used if an illegal value is supplied.
if (ch == 1)
ch_V = 1;
else
ch_V = 0;
}
uint16_t ADC::readChannel(uint8_t ch)
{
// Adapted from Mikko Karvonen's MCP3204 code,
// https://github.com/onttoni/mcp3204.git
// There's no multi-threading, so static variables are fine
static uint8_t spi_tx;
static uint8_t rx1;
static uint8_t rx2;
// Reads the specified channel of the A/D converter
SPI.beginTransaction(settings);
digitalWrite(csPin, LOW);
// Refer to FIGURE 6-1 in MCP3204 datasheet
// DEBUG: Gets stuck here when Reporter.startUDP (see below) is not commented out.
SPI.transfer(0x06);
// /DEBUG
spi_tx = ch << 6;
rx1 = SPI.transfer(spi_tx);
rx2 = SPI.transfer(0xFF);
digitalWrite(csPin, HIGH);
SPI.endTransaction();
return ((rx1 & 0x0F) << 8) | rx2;
}
// Provides access to a module running the WIZ5500 Ethernet chip
//------------------------------------------------------------------------
Reporter::Reporter(uint8_t csPin, uint8_t resetPin)
{
// Adapated from demo code at https://learn.adafruit.com/
// adafruit-wiz5500-wiznet-ethernet-featherwing/usage
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH);
delay(100);
digitalWrite(resetPin, LOW);
delay(100);
digitalWrite(resetPin, HIGH);
Ethernet.init(csPin);
// Give the Ethernet module time to boot up
delay(1000);
}
void Reporter::startUDP(byte mac[], IPAddress & ip, uint16_t localPort)
{
// Start the Ethernet connection
// DEBUG: Running this next line causes ADC reads to hang even with the udp lines below commented out.
Ethernet.begin(mac, ip);
// Start UDP listening
udp = EthernetUDP();
udp.begin(localPort);
}