Programuji právě snímač čáry, který má být jako slave I2C zařízení. A narazil jsem na principiální problém jak zajistit konzistenci dat. Do teď jsem všechny zařízení měl připojené přes UART a tam tento problém není. O co mi jde?
a) Připojení přes UART: master požádá o hodnotu, slave - tedy zařízení změří hodnotu a odešle zpět mastrovi. Vše OK.
b) Připojení přes I2C: master požádá o hodnotu (vyšle adresu čtení) a pak čte hodnotu. Nelze tedy měření provést až pro "žádosti" o hodnotu (měření trvá cca 5ms) a I2C master neví jak dlouho čekat. Proto slave provádí měření stále dokola a po přijetí žádosti odešle hodnotu. A tady je zakopaný pes. Pokud přijde požadavek na data v průběhu měření, tak se odešlou nesmysly. Proto jsem udělal bufer, do kterého se data přesunou až po dokončení měřeni (při zakázaném přerušení). Toto většinou funguje, ale principiální problém zůstává. Pokud se kopírování do buferu provede mezi vysílanými daty (odesílá se 2 nebo více bytů), pak to opět bude nesmyslná hodnota. Použití nějakého příznaku odesílání dat je taky problém - při odesílání slave neví, kolik bytů se bude odesílat.
Jak to elegantně vyřešit?
Zatím mě napadá jediné řešení (použité např. na sonarech SFRxx). Tam se odešle požadavek na měření. Master počká předepsanou dobu a pak teprve čte data. Ovšem tam, vše závisí na "slušném" chování mastra.
Slave I2C zařízení (konzistence dat)
Re: Slave I2C zařízení (konzistence dat)
Co takhle si před odesíláním udělat ještě jednu kopii?:-) Dá se předpokládat, že master bude chtít z hodnoty rozsekané do více bajtů přečíst vše.MartinL píše:Pokud se kopírování do buferu provede mezi vysílanými daty (odesílá se 2 nebo více bytů), pak to opět bude nesmyslná hodnota.
Alternativně mít ring buffer (jak se to řekne česky?), do kterého budu těch vzorků ukládat více a při requestu na čtení prvního bajt si zapamatovat ukazatel. Muselo by se ale počítat s tím, že se zbývající bajty přečtou dřív, než se ukazovaná pozice přepíše novými daty - to už je asi lepší to řešení s kopií.
“We’re all pathetic and creepy and can’t get girls. That’s why we fight robots.” –Kripke (TBBT)
Osobní web: adamh.cz
Osobní web: adamh.cz
Re: Slave I2C zařízení (konzistence dat)
Díky za tip, sice mě to také už napadlo, že v bych obsluze přerušení od I2C po přijetí adresy pro čtení celý bufer zkopíroval. Ale je mi to trošku proti srsti, takhle plýtvat pamětí (celý blok dat má cca 60B, a potřeboval bych ho tedy 3x) a já jsem holt vychován ještě postaru (tedy paměť má velikost v B a ne jak je dnes zvykem v GB).
Mám teď ještě jeden nápad, ale ten mi přijde taky trochu krkolomný. (po měření zakázat přerušení, otestovat příznak - probíhajícího odesílaní dat, není-li nastaven zkopírovat data a povolit přerušení; je-li nastaven, povolit přerušení a čekat na uvolnění příznaku probíhajícího odesílání dat. Příznak by se nahazoval v obsluze přerušení I2C po přijetí adresy pro čtení a shazoval po dokončení odesílání dat).
Mám teď ještě jeden nápad, ale ten mi přijde taky trochu krkolomný. (po měření zakázat přerušení, otestovat příznak - probíhajícího odesílaní dat, není-li nastaven zkopírovat data a povolit přerušení; je-li nastaven, povolit přerušení a čekat na uvolnění příznaku probíhajícího odesílání dat. Příznak by se nahazoval v obsluze přerušení I2C po přijetí adresy pro čtení a shazoval po dokončení odesílání dat).
Re: Slave I2C zařízení (konzistence dat)
Ahoj, nevím, jestli to k něčemu bude, ale měl jsem vyřešené v jednom pokusu tanku čtení ze dvou SRF02 následovně. Posílám jen funkci getRange(), kterou jsem volal v cyklu spolu s jinými servo() a report(). getRange() si sama ošetří kdy měřit a kdy přečíst výsledek. Základ jsem někde zkopíroval a pak upravil pro sebe:
Kód: Vybrat vše
/*
Generic example for the SRF modules 02, 08, 10 and 235.
Only the SRF08 uses the light saensor so when any other
range finder is used with this code the light reading will
be a constant value.
*/
#include <Wire.h>
#define srfAddress1 0x70 // Address of the N°1 SRF02
#define srfAddress2 0x71 // Address of the N°2 SRF02
#define cmdByte 0x00 // Command byte
#define rangeByte 0x02 // Byte for start of ranging data
byte highByte = 0x00; // Stores high byte from ranging
byte lowByte = 0x00; // Stored low byte from ranging
int rangeData1 = 0;
int rangeData2 = 0;
unsigned long lastRangeMeasure1 = 0;
unsigned long lastRangeMeasure2 = 0;
int lastRangePeriod = 200;
#include <Servo.h>
Servo myservo1;
Servo myservo2;
int pos1 = 90;
int pos2 = 90;
unsigned long lastReport = 0;
void setup(){
Wire.begin();
myservo1.attach(8); // attaches the servo on pin 9 to the servo object
myservo2.attach(9);
myservo1.write(90);
myservo2.write(90);
Serial.begin(57600);
//setAddress();
delay(100); // Waits to make sure everything is powered up before sending or receiving data
}
void loop(){
getRange(); // Calls a function to get range
servo();
report();
//delay(100); // Wait before looping
}
void getRange(){
if( (millis() - lastRangeMeasure1) > lastRangePeriod ){
measureRange1();
lastRangeMeasure1 = millis();
}
if( (millis() - lastRangeMeasure2) > lastRangePeriod ){
measureRange2();
lastRangeMeasure2 = millis();
}
if( (millis() - lastRangeMeasure1) > 100 ){
rangeData1 = readRange1(); // Calls a function to get range
// Serial.print("r1: ");Serial.println(rangeData1);
}
if( (millis() - lastRangeMeasure2) > 100 ){
rangeData2 = readRange2(); // Calls a function to get range
// Serial.print("r2: ");Serial.println(rangeData2);
}
}
void measureRange1(){ // This function gets a ranging from the SRF08
Wire.beginTransmission(srfAddress1); // Start communticating with SRF08
Wire.write(cmdByte); // Send Command Byte
Wire.write(0x51); // Send 0x51 to start a ranging
Wire.endTransmission();
//Serial.print(" m1 ");
}
void measureRange2(){ // This function gets a ranging from the SRF08
Wire.beginTransmission(srfAddress2); // Start communticating with SRF08
Wire.write(cmdByte); // Send Command Byte
Wire.write(0x51); // Send 0x51 to start a ranging
Wire.endTransmission();
//Serial.print(" m2 ");
}
int readRange1(){
int range = 0;
Wire.beginTransmission(srfAddress1); // start communicating with SRFmodule
Wire.write(rangeByte); // Call the register for start of ranging data
Wire.endTransmission();
Wire.requestFrom(srfAddress1, 2); // Request 2 bytes from SRF module
while(Wire.available() < 2); // Wait for data to arrive
highByte = Wire.read(); // Get high byte
lowByte = Wire.read(); // Get low byte
range = (highByte << 8) + lowByte; // Put them together
return(range); // Returns Range
// Serial.println("r1");
}
int readRange2(){
int range = 0;
Wire.beginTransmission(srfAddress2); // start communicating with SRFmodule
Wire.write(rangeByte); // Call the register for start of ranging data
Wire.endTransmission();
Wire.requestFrom(srfAddress2, 2); // Request 2 bytes from SRF module
while(Wire.available() < 2); // Wait for data to arrive
highByte = Wire.read(); // Get high byte
lowByte = Wire.read(); // Get low byte
range = (highByte << 8) + lowByte; // Put them together
return(range); // Returns Range
// Serial.println("r2");
}
-
- Příspěvky: 96
- Registrován: 24 úno 2013, 15:43
- Bydliště: Frydek - Mistek
- Kontaktovat uživatele:
Re: Slave I2C zařízení (konzistence dat)
Ahoj Martine
Což takhle něco velice nesportovního tedy
1. Master odešle požadavek na čtení
2. Slave mu odešle obsah bufferu
3. Slave přečte nové hodnoty
4. Slave uloží hodnoty do bufferu
5. Slave čeká na požadavek Mastera
Nesportovnost jasně tkví v tom, že se odesílají data získaná při minulém cyklu - je otázka jak moc to vadí při pravidelné aktualizaci se tato varianta jen nepatrně liší od varianty se periodickým čtením a synchronizací nějakým semaforem - dokonce je o něco lepší neb je explicitně jasné z které doby data pocházejí
Což takhle něco velice nesportovního tedy
1. Master odešle požadavek na čtení
2. Slave mu odešle obsah bufferu
3. Slave přečte nové hodnoty
4. Slave uloží hodnoty do bufferu
5. Slave čeká na požadavek Mastera
Nesportovnost jasně tkví v tom, že se odesílají data získaná při minulém cyklu - je otázka jak moc to vadí při pravidelné aktualizaci se tato varianta jen nepatrně liší od varianty se periodickým čtením a synchronizací nějakým semaforem - dokonce je o něco lepší neb je explicitně jasné z které doby data pocházejí
"The best computer language is a solder" - "Nejlepší programovací jazyk je pájka" - Bob Pease
http://petr-kubac.blog.cz/
http://petr-kubac.blog.cz/