I've been working with the lovely I2C_Anything.h (thanks to the great work and support from Nick over at http://www.gammon.com.au/forum/?id=10896&reply=9#reply9).. All working great, I was using Serial communication between Teensy 3.1 & mini pro but looking to replace with I2C - I was sending a file name across that was fine, but not managing to figure it out with the I2C_Anything technique.. here's some snippets:
MASTER
const uint8_t MaxMP3Name = 13;
//====================================
// DATA STRUCTURE FOR MP3 SLAVE
//====================================
struct SEND_MP3_STRUCTURE{
char Filename[MaxMP3Name];
uint8_t VolLeft;
uint8_t VolRight;
uint8_t Command;
};
SEND_MP3_STRUCTURE txMP3;
#define MP3_SLAVE_ADDRESS 77
const uint8_t PlayFile = 1;
const uint8_t PauseFile = 2;
const uint8_t StopFile = 3;
... etc
//#################################//
//## SEND MP3 COMMAND ##//
//#################################//
void sendMP3Command(String MP3File, uint8_t Command) {
char *TextArray[MaxMP3Name];
MP3File.toCharArray(TextArray, MaxMP3Name);
txMP3.Filename = TextArray;
txMP3.VolLeft = VolLeft;
txMP3.VolRight = VolRight;
txMP3.Command = Command;
Wire.beginTransmission(MP3_SLAVE_ADDRESS);
I2C_writeAnything(txMP3);
Wire.endTransmission(true);
}
...etc
... not entirely sure what i'm doing, I've tried most variations (using String in the struct vs char *Filename[] and various other attempts).
SLAVE
const uint8_t MaxMP3Name = 13;
//====================================
// RECEIVE DATA FORMAT
//====================================
struct RECEIVE_DATA_STRUCTURE{
char Filename[MaxMP3Name];
uint8_t VolLeft;
uint8_t VolRight;
uint8_t Command;
};
volatile RECEIVE_DATA_STRUCTURE RXdata;
#define SLAVE_ADDRESS 77
volatile uint8_t newData; // flag to detect I2C activity
// MAKE GLOBAL VERSIONS
String RX_Filename;
uint8_t RX_VolLeft = 30;
uint8_t RX_VolRight = 30;
uint8_t RX_Command = 0;
... etc
//#################################//
//## MASTER SENDING US DATA ##//
//#################################//
void onReceiveEvent(int numbytes){
if(numbytes == 16){
I2C_readAnything(RXdata);
newData = 2;
}
}
... etc
void loop(){
if (newData==2){// I2C received Data
RX_Filename = RXdata.Filename;
RX_VolLeft = RXdata.VolLeft;
RX_VolRight = RXdata.VolRight;
RX_Command = RXdata.Command;
newData = 0; // Clear data sent marker
}
}
... etc
Hopefully you'll be able to see pretty quickly what i'm trying to do and the method I should be using to do it..
Thanks for any insights
Cheers
Andy
Sorry, still getting used to this comment vs editing questions business, didn't realise it would add my comment when I hit enter so it cut me off... here's full comment:
Hiya Nick, thanks for your suggestion, How you've recommended it is actually how I tried it originally (I don't like using Strings either) - which just ends up giving me the error:
"invalid conversion from 'volatile char*' to 'const char*' [-fpermissive]"
(on the Slave) - obviously the RXdata is updated during the interrupt so can't leave it out (despite the fact it compiles - but doesnt work)..
I got it working soon after I posted by breaking down the filename in the struct to separate chars, then assembling back into char array in a function I made.
That seemed to work fine, but only if I added null char at as the last char (0x00) - I can get the char Filename[MaxMP3Name];
working, but only if I lose the volatile declaration, and it skips the last char.
Thanks for any further help Nick, I really appreciate all you do for the community and I know you're the best guy to help me (not to take anything away from anyone else that wants to jump in ;)
Current solution i'm using that avoids the volatile erros
Obviously could be a for loop etc but I wrote it out this way just to debug and see where the issue was. Not perfect, but breaking it down this way seems to be overcoming the issue of trying to do anything with the volatile variable. (and i've got so much to figure out for so many other parts of the project that I was thinking i'd come back to it later once i'm done with other bits).. Cheers
//#################################//
//## SEND MP3 COMMAND ##//
//#################################//
void sendMP3Command(String MP3File, uint8_t Command) {
char FileName[8];
MP3File.toCharArray(FileName, MaxMP3Name+1);
txMP3.File1 = FileName[0];
txMP3.File2 = FileName[1];
txMP3.File3 = FileName[2];
txMP3.File4 = FileName[3];
txMP3.File5 = FileName[4];
txMP3.File6 = FileName[5];
txMP3.File7 = FileName[6];
txMP3.File8 = FileName[7];
txMP3.VolLeft = VolLeft;
txMP3.VolRight = VolRight;
txMP3.Command = Command;
StartMicros = micros();
Wire.beginTransmission(MP3_SLAVE_ADDRESS);
I2C_writeAnything(txMP3);
Wire.endTransmission(true);
EndMicros = micros();
//Serial.print("MP3 Packet Size: "); Serial.println(sizeof(txMP3));
//Serial.print("Sending Command To MP3: "); Serial.print(MP3File);Serial.print(" Command; "); Serial.print(txMP3.Command);Serial.print(" Time; "); Serial.print(EndMicros-StartMicros);Serial.println("uS ");
}
... Oh, and on the slave end, I changed the numbytes to be sizeof, but as you say Nick, not even any need for that, i'm not using it on any of my other I2C slaves all running in the project (5 X MCU core system). the filename is then pulled from the I2C array in a siimilar (debugging) way as the master packs them in
//##############################//
// RECONSTRUCT FILENAME
//##############################//
String getFilename(){
char FileName[] = {
RXdata.File1,
RXdata.File2,
RXdata.File3,
RXdata.File4,
RXdata.File5,
RXdata.File6,
RXdata.File7,
RXdata.File8,
0x00
};
return FileName;
}
//#################################//
//## MASTER REQUESTING DATA ##//
//#################################//
void onRequestEvent(void){
I2C_singleWriteAnything(TXdata);
newData = 1;
}
//#################################//
//## MASTER SENDING US DATA ##//
//#################################//
void onReceiveEvent(int numbytes){
if(numbytes == sizeof RXdata){
I2C_readAnything(RXdata);
newData = 2;
}
}