View attachment mcuUart.zip
Here is the I2C controller WIP
the gpios, and begin functions run through crc checks to make sure there will be no corruption (if ever) and no, theres been none at all so far (knock on wood)
uarts, and spi busses dont do crc for streaming
im sure there is great potential for this type of code, having extra spi busses and uarts from a spare mcu accessible within the same local sketch, it's alot cheaper to add a teensy than to buy an i2cuart adaptor with flaky library code, with benefits of several integrated hardware features... i plan to extend it with additional features if the need arises, but, just think of the gpio accessibility of it. it's alot easier to control single, or many t3.5/3.6 over i2c with 60 gpios than it is to run 4 mcp23017's to gain 64 gpios, in terms of accessibility, and small footprint, 2 teensies can easily replace an 8 chip bank of mcp23017 port expanders for about 120gpio access using a single host, a single sketch, a small footprint, a single class per teensy slave, with many additional hardware benefits included. Just try to control 8 different types of mcp23017 using adafruit's library, you will see how simple my code here will stand out regarding that:
gpio <-- was the initializer, but you know as well as I that you can call it whatever you want
expander1? ok..
expander1.pinMode(13,OUTPUT);
expander1.digitalRead(13);
expander1.digitalWrite(13,HIGH);
expander1.analogRead(A0);
expander1.analogWrite(A0, 255);
i try to make it simple ;P
Also paul, the test with the i2c issue on 3.5 at 120mhz with the i2c bus locking up was tested on latest teensyduino using Faster, constantly read/writing to the uart channel, which never happened on the mega
my initial attempts were to delay some of the transactions but it didnt work, my 2nd test was to drop to 24mhz cpu and thats when it was stable, i presume this is an issue with code being slave needs to be clocked lower, not sure, im not an expert on that.
btw...
The file here is the library, this is run on the master, be it arduino or teensy, both use Wire.h (i didnt use i2c_t3 because it doesnt support Wire onreceive etc for slave support???)
The slave sketch is posted in CODE brackets, the initializers can be set using the posts above where i given examples
Like i said, i dont have time to do readmes, headers, or prepare example files, or rename the files themself (mcuUart.h) it should have a new name since initially i started it as a remote uart controller cuz i needed additional uarts, also a benefit is the high speed uart access teensy->teensy, FIFO, and huge buffers over i2c that you cannot obtain using other expensive commercial single hardware interface use chips. I mean really, who does or has a chip in the market capable of 625K baud serial device transfers over the i2c bus?? lol
I've also looked around, I dont even think i2c to SPI bus chips exist, but here we have a 2-wire SPI bus.
Benefits?? Sure...
Lets say you have an SPI device and you dont have additional busses for it, or no available gpios for CS, OR, perhaps you plan to install the device further away..... and want to use less wiring back to your host...
this is ideal
Enjoy it guys! Leave feedback if anything is worthwhile adding for support, ill mark it in my todo list
Tony
Code:
#include <Wire.h>
#include <SPI.h>
volatile uint8_t PORT;
volatile uint8_t PIN;
volatile uint8_t bytes[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
volatile uint32_t spi_speed = 4000000;
volatile uint8_t spi_byte;
uint8_t checksum;
void setup() {
Wire.begin(1);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
SPI.begin();
Serial.begin(115200);
}
void loop() {
}
void receiveEvent(int howMany) {
bytes[0] = Wire.read();
switch ( bytes[0] ) {
case 0: { // COMMAND BYTE
if (Wire.available() != 11) { // wrong length of bytes for CMD/CRC, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
checksum = 0x00;
for ( uint8_t i = 1; i <= 11; i++ ) bytes[i] = Wire.read();
for ( uint8_t i; i <= 10; i++ ) checksum ^= bytes[i];
Serial.print(bytes[0]); Serial.print(" : "); Serial.print(bytes[1]); Serial.print(" : "); Serial.print(bytes[2]); Serial.print(" : "); Serial.print(bytes[3]); Serial.print(" : "); Serial.print(bytes[4]); Serial.print(" : "); Serial.print(bytes[5]); Serial.print(" : "); Serial.print(bytes[6]); Serial.print(" : "); Serial.print(bytes[7]); Serial.print(" : "); Serial.print(bytes[8]); Serial.print(" : "); Serial.print(bytes[9]); Serial.print(" : "); Serial.print(bytes[10]); Serial.print(" : "); Serial.println(bytes[11]);
if ( bytes[11] != checksum ) break; // bad checksum exit
switch ( bytes[1] ) { // FUNCTION
case 1: { // SERIAL PORT AND BAUD RATE
uint8_t baudrate_split[4] = {bytes[3], bytes[4], bytes[5], bytes[6]};
uint32_t baudrate = *(uint32_t*)&baudrate_split;
switch ( bytes[2] ) {
case 0: {
Serial.begin(baudrate); break;
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
Serial1.begin(baudrate); break;
}
case 2: {
Serial2.begin(baudrate); break;
}
case 3: {
Serial3.begin(baudrate); break;
}
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 4: {
Serial4.begin(baudrate); break;
}
case 5: {
Serial5.begin(baudrate); break;
}
case 6: {
Serial6.begin(baudrate); break;
}
#endif
}
break;
}
case 2: { // PINMODE
pinMode(bytes[2], bytes[3]); break;
}
case 3: { // DIGITALWRITE
digitalWrite(bytes[2], bytes[3]); break;
}
case 4: { // SPI begin()
switch ( bytes[2] ) { // PORT
case 0: { // SPI
SPI.begin(); break;
}
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: { // SPI
SPI1.begin(); break;
}
case 2: { // SPI
SPI2.begin(); break;
}
#endif
}
break;
}
case 5: { // SPI beginTransaction
uint8_t speed_split[4] = {bytes[3], bytes[4], bytes[5], bytes[6]}, msblsb = bytes[7], mode = bytes[8], port = bytes[2];
spi_speed = *(uint32_t*)&speed_split;
switch ( port ) { // PORT
case 0: { // SPI
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); break;
}
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: { // SPI1
SPI1.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); break;
}
case 2: { // SPI2
SPI2.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); break;
}
#endif
}
break;
}
}
break;
}
case 1: { // SEND A SERIAL BYTE
if (Wire.available() != 2) {
// wrong length of bytes for serial, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
for ( uint8_t i = 1; i <= 2; i++ ) bytes[i] = Wire.read();
switch ( bytes[1] ) {
case 0: {
Serial.write(bytes[2]); break;
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
Serial1.write(bytes[2]); break;
}
case 2: {
Serial2.write(bytes[2]); break;
}
case 3: {
Serial3.write(bytes[2]); break;
}
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 4: {
Serial4.write(bytes[2]); break;
}
case 5: {
Serial5.write(bytes[2]); break;
}
case 6: {
Serial6.write(bytes[2]); break;
}
#endif
}
break;
}
case 2: { // READ A SERIAL BYTE
if (Wire.available() != 1) {
// wrong length of bytes for serial read, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
PORT = Wire.read(); break;
}
case 3: { // AVAILABLE SERIAL BYTES
if (Wire.available() != 1) {
// wrong length of bytes for serial available, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
PORT = Wire.read(); break;
}
case 4: { // PEEK SERIAL BYTE
if (Wire.available() != 1) {
// wrong length of bytes for serial peek, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
PORT = Wire.read(); break;
}
case 5: { // digitalRead pin
if (Wire.available() != 1) {
// wrong length of bytes for digitalRead, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
PIN = Wire.read(); break;
}
case 6: { // analogRead pin
if (Wire.available() != 1) {
// wrong length of bytes for analogRead, FLUSH and EXIT!
while ( Wire.available() > 0 ) Wire.read();
return;
}
PIN = Wire.read(); break;
}
case 7: { // spi.transfer
PORT = Wire.read(); uint8_t toSend = Wire.read(); spi_byte = SPI.transfer(toSend); break;
}
case 8: { // spi.endTransaction
PORT = Wire.read();
switch ( PORT ) {
case 0: {
SPI.endTransaction(); break;
}
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
SPI1.endTransaction(); break;
}
case 2: {
SPI2.endTransaction(); break;
}
#endif
}
break;
}
case 9: { // analogWrite
PIN = Wire.read();
uint8_t value_split[2] = {(uint8_t)Wire.read(), (uint8_t)Wire.read()};
uint16_t value = *(uint16_t*)&value_split;
analogWrite(PIN, value);
break;
}
// case 10: { // analogWriteResolution
// PIN = Wire.read();
// uint8_t res = Wire.read();
// analogWriteResolution(res);
// break;
// }
}
}
void requestEvent() {
switch ( bytes[0] ) { // COMMAND BYTE
case 0x02: { // break; read byte from serial
switch ( PORT ) {
case 0: {
Wire.write(Serial.read()); break;
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
Wire.write(Serial1.read()); break;
}
case 2: {
Wire.write(Serial2.read()); break;
}
case 3: {
Wire.write(Serial3.read()); break;
}
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 4: {
Wire.write(Serial4.read()); break;
}
case 5: {
Wire.write(Serial5.read()); break;
}
case 6: {
Wire.write(Serial6.read()); break;
}
#endif
}
break;
}
case 0x03: { // break; available bytes on serial port
switch ( PORT ) {
case 0: {
Wire.write(Serial.available()); break;
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
Wire.write(Serial1.available()); break;
}
case 2: {
Wire.write(Serial2.available()); break;
}
case 3: {
Wire.write(Serial3.available()); break;
}
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 4: {
Wire.write(Serial4.available()); break;
}
case 5: {
Wire.write(Serial5.available()); break;
}
case 6: {
Wire.write(Serial6.available()); break;
}
#endif
}
break;
}
case 0x04: { // break; peek byte on serial port
switch ( PORT ) {
case 0: {
Wire.write(Serial.peek()); break;
}
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 1: {
Wire.write(Serial1.peek()); break;
}
case 2: {
Wire.write(Serial2.peek()); break;
}
case 3: {
Wire.write(Serial3.peek()); break;
}
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 4: {
Wire.write(Serial4.peek()); break;
}
case 5: {
Wire.write(Serial5.peek()); break;
}
case 6: {
Wire.write(Serial6.peek()); break;
}
#endif
}
break;
}
case 0x05: { // break; digital pin status
Wire.write(digitalRead(PIN)); break;
}
case 0x06: { // break; analog pin value
uint16_t value = analogRead(PIN);
Wire.write((uint8_t)(value >> 8));
Wire.write((uint8_t)value);
break;
}
case 0x07: { // spi byte return
Wire.write(spi_byte); break;
}
}
}