Hallo Rudolf, hallo Tobias,
ok, dann hier die Codeänderungen. Ich möchte es noch beta nennen, da sicherlich noch optimierbar. Für TX, also Senderichtung habe ich es auch gleich eingebaut. Vielleicht kann Martin das Timingtechnisch nochmal für den Normalfall, also ohne PLL Lock Problem, mal gegen checken.
Mit
attr CUL_0 verbose 2
für den CUL (CUL_0 ggf. anpassen) werden die eingebauten Meldungen ins Log geschrieben.
Ausgegeben werden:
PLLERR , wenn der Registerzustand aus meinen Logs im RX State erkannt wird und aufgrund dessen rf_asksin_init aufgerufen wird (die harte Methode, da damit auch SRES ausgeführt wird).
PLLNOLOCK , wenn der CUL ohne PLL Lock erwischt wird. Dann wird die Kalibrierung versucht.
PLLLOCKFAIL , wenn mehrere Versuche des Kalibrierens nicht zu einem erfolgreichen PLL Lock führen.
@Rudolf: Danke für den Speicherhinweis! Wäre schön, wenn Du das Speichertechnisch für CUL_V2 mal checken könntest. Die Ausgaben zu size verstehe ich noch nicht ganz und möchte nicht fehlinterpretieren.
@Tobias: Danke für Deine Problemnachricht. Zur Fritz!Box 7390 darf ich aus eigener Erfahrung sagen, dass die USB Stromversorgung da auch eine Rolle spielen kann (siehe auch Rudolfs und Jens Tipps und Hinweise zur Stromversorgung), zumindest mit USB-Sticks (CUL war noch nie daran angeschlossen) hatte ich da Probleme, die sich mit einem dickeren Netzteil beheben ließen. Das original Netzteil hatte das auch anfangs mit gemacht aber ist dann nach ca. 1 Jahr Betrieb etwas eingebrochen. Wenn Du also mehr als nur den CUL daran hängen hast, dann kann die Stromversorgung auch Problemursache sein.
Wenn Du nicht gerade einen CUL_V2 (und damit eventuell zu wenig Programmspeicherplatz) hasst, dann würde ich mich freuen, von Deinen Erfahrungen mit der Firmwareänderung zu lesen. Bitte auch den verbose Modus für den CUL auf 2 setzen, damit es im Log auch sichtbar wird.
Hier der diff zu rf_asksin.c:
--- rf_asksin.c 2014-03-13 21:49:42.000000000 +0100
+++ clib/rf_asksin.c 2014-05-27 23:03:27.896030622 +0200
@@ -58,6 +58,10 @@
#endif
static void rf_asksin_reset_rx(void);
+static void rf_asksin_toRX(void);
+static void rf_asksin_toTX(void);
+static uint8_t asksin_checkPLL(void); // noansi: returns 0 on success
+
void
rf_asksin_init(void)
@@ -90,24 +94,26 @@
}
}
#endif
-
+
ccStrobe( CC1100_SCAL );
my_delay_ms(4);
// enable RX, but don't enable the interrupt
- do {
- ccStrobe(CC1100_SRX);
- } while (cc1100_readReg(CC1100_MARCSTATE) != MARCSTATE_RX);
+ // noansi: check PLL is in Lock in RX
+ rf_asksin_toRX();
}
+
static void
rf_asksin_reset_rx(void)
{
+ ccStrobe( CC1100_SIDLE ); // noansi: if stuck in RX after RX OVERFLOW as described in CC1101 errata -> do SFRX only in IDLE as CC1101 doc
ccStrobe( CC1100_SFRX );
- ccStrobe( CC1100_SIDLE );
- ccStrobe( CC1100_SNOP );
- ccStrobe( CC1100_SRX );
+ //ccStrobe( CC1100_SIDLE );
+ //ccStrobe( CC1100_SNOP );
+ //ccStrobe( CC1100_SRX );
+ rf_asksin_toRX(); // noansi: try to set RX with calibration
}
void
@@ -143,9 +149,7 @@
CC1100_DEASSERT;
- do {
- ccStrobe(CC1100_SRX);
- } while (cc1100_readReg(CC1100_MARCSTATE) != MARCSTATE_RX);
+ rf_asksin_toRX();
last_enc = msg[1];
msg[1] = (~msg[1]) ^ 0x89;
@@ -178,14 +182,33 @@
}
switch(cc1100_readReg( CC1100_MARCSTATE )) {
+ case MARCSTATE_RX:
+ // noansi: try init, if stuck in RX State with no PLL Lock as seen in extended read timeout logging
+ l = cc1100_readReg( CC1100_FSCAL1 );
+ if (l == 0x3f) { // noansi: no PLL Lock as described in CC1101 errata
+ l = cc1100_readReg( CC1100_FSCAL3 );
+ if (l == 0xaf) { // noansi: saw this too, if no data is received any more for a long period of time (up to 2 hours)
+ DS_P(PSTR("PLLERR\r\n"));
+ rf_asksin_init(); // noansi: try init to recover
+ return;
+ }
+ }
+ break;
case MARCSTATE_RXFIFO_OVERFLOW:
+ ccStrobe( CC1100_SIDLE ); // noansi: if stuck in RX after RX OVERFLOW as described in CC1101 errata -> do SFRX only in IDLE as CC1101 doc
ccStrobe( CC1100_SFRX );
case MARCSTATE_IDLE:
- ccStrobe( CC1100_SIDLE );
- ccStrobe( CC1100_SNOP );
- ccStrobe( CC1100_SRX );
+ //ccStrobe( CC1100_SIDLE );
+ //ccStrobe( CC1100_SNOP );
+ //ccStrobe( CC1100_SRX );
+ rf_asksin_toRX(); // noansi: try to set RX with calibration
break;
}
+
+ if (asksin_checkPLL()) // noansi: check PLL is in Lock
+ {
+ rf_asksin_toRX(); // noansi: try to set RX with calibration
+ }
}
void
@@ -218,10 +241,8 @@
msg[l] = msg[l] ^ ctl;
- // enable TX, wait for CCA
- do {
- ccStrobe(CC1100_STX);
- } while (cc1100_readReg(CC1100_MARCSTATE) != MARCSTATE_TX);
+ // noansi: set TX with check/try PLL is in Lock in TX
+ rf_asksin_toTX();
if (ctl & (1 << 4)) { // BURST-bit set?
// According to ELV, devices get activated every 300ms, so send burst for 360ms
@@ -252,14 +273,118 @@
}
if(asksin_on) {
- do {
- ccStrobe(CC1100_SRX);
- } while (cc1100_readReg(CC1100_MARCSTATE) != MARCSTATE_RX);
+ // noansi: set RX with check/try PLL is in Lock in RX
+ rf_asksin_toRX();
} else {
set_txrestore();
}
}
+static void
+rf_asksin_toRX(void)
+{
+ uint8_t n;
+ uint8_t t;
+
+ // noansi: set RX with check/try PLL is in Lock in RX
+ n = 5; // noansi: Try to set several times before giving up
+ do {
+ // enable RX
+ t = 255;
+ do {
+ ccStrobe(CC1100_SRX);
+ if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_RX) break;
+ my_delay_us(5);
+ } while (--t);
+
+ //if (!t) DS_P(PSTR("PLLNORX\r\n"));
+
+ if (!asksin_checkPLL()) return;
+ } while (--n);
+
+ //if (!n) DS_P(PSTR("PLLRXFAIL\r\n"));
+}
+
+static void
+rf_asksin_toTX(void)
+{
+ uint8_t n;
+ uint8_t t;
+
+ // noansi: set TX with check/try PLL is in Lock in TX
+ n = 5; // noansi: Try to set several times before giving up
+ do {
+ // enable TX, wait for CCA
+ t = 255;
+ do {
+ ccStrobe(CC1100_STX);
+ if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_TX) break;
+ my_delay_us(5);
+ } while (--t);
+
+ //if (!t) DS_P(PSTR("PLLNOTX\r\n"));
+
+ if (!asksin_checkPLL()) return;
+ } while (--n);
+
+ //if (!n) DS_P(PSTR("PLLTXFAIL\r\n"));
+}
+
+static uint8_t
+asksin_checkPLL(void) // noansi: returns 0 on success
+{
+ uint8_t n;
+ uint8_t l;
+
+ // noansi: check PLL Lock and try to calibrate. Possibly restoring a saved calibration could be faster...
+ n = 5; // noansi: Try to recover several times before giving up
+ do
+ {
+ l = cc1100_readReg( CC1100_FSCAL1 );
+ if (l != 0x3f) return 0; // noansi: PLL in Lock as described in CC1101 doc and errata
+
+ // noansi: try to recover as no PLL Lock as described in CC1101 doc and errata
+ ccStrobe( CC1100_SIDLE );
+ DS_P(PSTR("PLLNOLOCK\r\n"));
+ // noansi: wait idle state, is it needed here?
+ l = 255;
+ do
+ {
+ if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_IDLE) break;
+ my_delay_us(1);
+ }
+ while (--l);
+
+ ccStrobe( CC1100_SCAL ); // noansi: Try Calibration
+
+ //if (!l) DS_P(PSTR("PLLNOIDLE\r\n"));
+
+ //my_delay_ms(1); // noansi: maybe waiting gives a better calibration instead of polling the state (noise)
+
+ // noansi: wait idle state -> calibration finished
+ l = 255;
+ do
+ {
+ if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_IDLE) break;
+ my_delay_us(10);
+ }
+ while (--l);
+
+ //if (!l) DS_P(PSTR("PLLNOCALIDLE\r\n"));
+ }
+ while (--n);
+
+ //rf_asksin_init(); // noansi: Try Init ... no could flood stack recursively...
+
+ l = cc1100_readReg( CC1100_FSCAL1 );
+ if (l != 0x3f) return 0; // noansi: PLL in Lock as described in CC1101 doc and errata
+
+ DS_P(PSTR("PLLLOCKFAIL\r\n"));
+
+ return 1; // noansi: error, no PLL Lock
+}
+
+
void
asksin_func(char *in)
{
Für die, die die komplette geänderte rf_asksin.c ansehen möchten:
#include "board.h"
#ifdef HAS_ASKSIN
#include <string.h>
#include <avr/pgmspace.h>
#include "cc1100.h"
#include "delay.h"
#include "rf_receive.h"
#include "display.h"
#include "rf_asksin.h"
uint8_t asksin_on = 0;
const uint8_t PROGMEM ASKSIN_CFG[] = {
0x00, 0x07,
0x02, 0x2e,
0x03, 0x0d,
0x04, 0xE9,
0x05, 0xCA,
0x07, 0x0C,
0x0B, 0x06,
0x0D, 0x21,
0x0E, 0x65,
0x0F, 0x6A,
0x10, 0xC8,
0x11, 0x93,
0x12, 0x03,
0x15, 0x34,
0x17, 0x33, // go into RX after TX, CCA; EQ3 uses 0x03
0x18, 0x18,
0x19, 0x16,
0x1B, 0x43,
0x21, 0x56,
0x25, 0x00,
0x26, 0x11,
0x29, 0x59,
0x2c, 0x81,
0x2D, 0x35,
0x3e, 0xc3
};
#ifdef HAS_ASKSIN_FUP
const uint8_t PROGMEM ASKSIN_UPDATE_CFG[] = {
0x0B, 0x08,
0x10, 0x5B,
0x11, 0xF8,
0x15, 0x47,
0x19, 0x1D,
0x1A, 0x1C,
0x1B, 0xC7,
0x1C, 0x00,
0x1D, 0xB2,
0x21, 0xB6,
0x23, 0xEA,
};
static unsigned char asksin_update_mode = 0;
#endif
static void rf_asksin_reset_rx(void);
static void rf_asksin_toRX(void);
static void rf_asksin_toTX(void);
static uint8_t asksin_checkPLL(void); // noansi: returns 0 on success
void
rf_asksin_init(void)
{
EIMSK &= ~_BV(CC1100_INT); // disable INT - we'll poll...
SET_BIT( CC1100_CS_DDR, CC1100_CS_PIN ); // CS as output
CC1100_DEASSERT; // Toggle chip select signal
my_delay_us(30);
CC1100_ASSERT;
my_delay_us(30);
CC1100_DEASSERT;
my_delay_us(45);
ccStrobe( CC1100_SRES ); // Send SRES command
my_delay_us(100);
// load configuration
for (uint8_t i = 0; i < sizeof(ASKSIN_CFG); i += 2) {
cc1100_writeReg( pgm_read_byte(&ASKSIN_CFG[i]),
pgm_read_byte(&ASKSIN_CFG[i+1]) );
}
#ifdef HAS_ASKSIN_FUP
if (asksin_update_mode) {
for (uint8_t i = 0; i < sizeof(ASKSIN_UPDATE_CFG); i += 2) {
cc1100_writeReg( pgm_read_byte(&ASKSIN_UPDATE_CFG[i]),
pgm_read_byte(&ASKSIN_UPDATE_CFG[i+1]) );
}
}
#endif
ccStrobe( CC1100_SCAL );
my_delay_ms(4);
// enable RX, but don't enable the interrupt
// noansi: check PLL is in Lock in RX
rf_asksin_toRX();
}
static void
rf_asksin_reset_rx(void)
{
ccStrobe( CC1100_SIDLE ); // noansi: if stuck in RX after RX OVERFLOW as described in CC1101 errata -> do SFRX only in IDLE as CC1101 doc
ccStrobe( CC1100_SFRX );
//ccStrobe( CC1100_SIDLE );
//ccStrobe( CC1100_SNOP );
//ccStrobe( CC1100_SRX );
rf_asksin_toRX(); // noansi: try to set RX with calibration
}
void
rf_asksin_task(void)
{
uint8_t msg[MAX_ASKSIN_MSG];
uint8_t this_enc, last_enc;
uint8_t rssi;
uint8_t l;
if(!asksin_on)
return;
// see if a CRC OK pkt has been arrived
if (bit_is_set( CC1100_IN_PORT, CC1100_IN_PIN )) {
msg[0] = cc1100_readReg( CC1100_RXFIFO ) & 0x7f; // read len
if (msg[0] >= MAX_ASKSIN_MSG) {
// Something went horribly wrong, out of sync?
rf_asksin_reset_rx();
return;
}
CC1100_ASSERT;
cc1100_sendbyte( CC1100_READ_BURST | CC1100_RXFIFO );
for (uint8_t i=0; i<msg[0]; i++) {
msg[i+1] = cc1100_sendbyte( 0 );
}
rssi = cc1100_sendbyte( 0 );
/* LQI = */ cc1100_sendbyte( 0 );
CC1100_DEASSERT;
rf_asksin_toRX();
last_enc = msg[1];
msg[1] = (~msg[1]) ^ 0x89;
for (l = 2; l < msg[0]; l++) {
this_enc = msg[l];
msg[l] = (last_enc + 0xdc) ^ msg[l];
last_enc = this_enc;
}
msg[l] = msg[l] ^ msg[2];
if (tx_report & REP_BINTIME) {
DC('a');
for (uint8_t i=0; i<=msg[0]; i++)
DC( msg[i] );
} else {
DC('A');
for (uint8_t i=0; i<=msg[0]; i++)
DH2( msg[i] );
if (tx_report & REP_RSSI)
DH2(rssi);
DNL();
}
}
switch(cc1100_readReg( CC1100_MARCSTATE )) {
case MARCSTATE_RX:
// noansi: try init, if stuck in RX State with no PLL Lock as seen in extended read timeout logging
l = cc1100_readReg( CC1100_FSCAL1 );
if (l == 0x3f) { // noansi: no PLL Lock as described in CC1101 errata
l = cc1100_readReg( CC1100_FSCAL3 );
if (l == 0xaf) { // noansi: saw this too, if no data is received any more for a long period of time (up to 2 hours)
DS_P(PSTR("PLLERR\r\n"));
rf_asksin_init(); // noansi: try init to recover
return;
}
}
break;
case MARCSTATE_RXFIFO_OVERFLOW:
ccStrobe( CC1100_SIDLE ); // noansi: if stuck in RX after RX OVERFLOW as described in CC1101 errata -> do SFRX only in IDLE as CC1101 doc
ccStrobe( CC1100_SFRX );
case MARCSTATE_IDLE:
//ccStrobe( CC1100_SIDLE );
//ccStrobe( CC1100_SNOP );
//ccStrobe( CC1100_SRX );
rf_asksin_toRX(); // noansi: try to set RX with calibration
break;
}
if (asksin_checkPLL()) // noansi: check PLL is in Lock
{
rf_asksin_toRX(); // noansi: try to set RX with calibration
}
}
void
asksin_send(char *in)
{
uint8_t msg[MAX_ASKSIN_MSG];
uint8_t ctl;
uint8_t l;
uint8_t hblen = fromhex(in+1, msg, MAX_ASKSIN_MSG-1);
if ((hblen-1) != msg[0]) {
// DS_P(PSTR("LENERR\r\n"));
return;
}
// in AskSin mode already?
if(!asksin_on) {
rf_asksin_init();
my_delay_ms(3); // 3ms: Found by trial and error
}
ctl = msg[2];
// "crypt"
msg[1] = (~msg[1]) ^ 0x89;
for (l = 2; l < msg[0]; l++)
msg[l] = (msg[l-1] + 0xdc) ^ msg[l];
msg[l] = msg[l] ^ ctl;
// noansi: set TX with check/try PLL is in Lock in TX
rf_asksin_toTX();
if (ctl & (1 << 4)) { // BURST-bit set?
// According to ELV, devices get activated every 300ms, so send burst for 360ms
for(l = 0; l < 3; l++)
my_delay_ms(120); // arg is uint_8, so loop
} else {
my_delay_ms(10);
}
// send
CC1100_ASSERT;
cc1100_sendbyte(CC1100_WRITE_BURST | CC1100_TXFIFO);
for(uint8_t i = 0; i < hblen; i++) {
cc1100_sendbyte(msg[i]);
}
CC1100_DEASSERT;
// wait for TX to finish
while(cc1100_readReg( CC1100_MARCSTATE ) == MARCSTATE_TX)
;
if (cc1100_readReg( CC1100_MARCSTATE ) == MARCSTATE_TXFIFO_UNDERFLOW) {
ccStrobe( CC1100_SFTX );
ccStrobe( CC1100_SIDLE );
ccStrobe( CC1100_SNOP );
}
if(asksin_on) {
// noansi: set RX with check/try PLL is in Lock in RX
rf_asksin_toRX();
} else {
set_txrestore();
}
}
static void
rf_asksin_toRX(void)
{
uint8_t n;
uint8_t t;
// noansi: set RX with check/try PLL is in Lock in RX
n = 5; // noansi: Try to set several times before giving up
do {
// enable RX
t = 255;
do {
ccStrobe(CC1100_SRX);
if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_RX) break;
my_delay_us(5);
} while (--t);
//if (!t) DS_P(PSTR("PLLNORX\r\n"));
if (!asksin_checkPLL()) return;
} while (--n);
//if (!n) DS_P(PSTR("PLLRXFAIL\r\n"));
}
static void
rf_asksin_toTX(void)
{
uint8_t n;
uint8_t t;
// noansi: set TX with check/try PLL is in Lock in TX
n = 5; // noansi: Try to set several times before giving up
do {
// enable TX, wait for CCA
t = 255;
do {
ccStrobe(CC1100_STX);
if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_TX) break;
my_delay_us(5);
} while (--t);
//if (!t) DS_P(PSTR("PLLNOTX\r\n"));
if (!asksin_checkPLL()) return;
} while (--n);
//if (!n) DS_P(PSTR("PLLTXFAIL\r\n"));
}
static uint8_t
asksin_checkPLL(void) // noansi: returns 0 on success
{
uint8_t n;
uint8_t l;
// noansi: check PLL Lock and try to calibrate. Possibly restoring a saved calibration could be faster...
n = 5; // noansi: Try to recover several times before giving up
do
{
l = cc1100_readReg( CC1100_FSCAL1 );
if (l != 0x3f) return 0; // noansi: PLL in Lock as described in CC1101 doc and errata
// noansi: try to recover as no PLL Lock as described in CC1101 doc and errata
ccStrobe( CC1100_SIDLE );
DS_P(PSTR("PLLNOLOCK\r\n"));
// noansi: wait idle state, is it needed here?
l = 255;
do
{
if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_IDLE) break;
my_delay_us(1);
}
while (--l);
ccStrobe( CC1100_SCAL ); // noansi: Try Calibration
//if (!l) DS_P(PSTR("PLLNOIDLE\r\n"));
//my_delay_ms(1); // noansi: maybe waiting gives a better calibration instead of polling the state (noise)
// noansi: wait idle state -> calibration finished
l = 255;
do
{
if (cc1100_readReg(CC1100_MARCSTATE) == MARCSTATE_IDLE) break;
my_delay_us(10);
}
while (--l);
//if (!l) DS_P(PSTR("PLLNOCALIDLE\r\n"));
}
while (--n);
//rf_asksin_init(); // noansi: Try Init ... no could flood stack recursively...
l = cc1100_readReg( CC1100_FSCAL1 );
if (l != 0x3f) return 0; // noansi: PLL in Lock as described in CC1101 doc and errata
DS_P(PSTR("PLLLOCKFAIL\r\n"));
return 1; // noansi: error, no PLL Lock
}
void
asksin_func(char *in)
{
#ifndef HAS_ASKSIN_FUP
if(in[1] == 'r') { // Reception on
#else
if((in[1] == 'r') || (in[1] == 'R')) { // Reception on
if (in[1] == 'R') {
asksin_update_mode = 1;
} else {
asksin_update_mode = 0;
}
#endif
rf_asksin_init();
asksin_on = 1;
} else if(in[1] == 's') { // Send
asksin_send(in+1);
} else { // Off
asksin_on = 0;
}
}
#endif
Erfahrungsberichte und Verbesserungsvorschläge werden gerne entgegen genommen.
Gruß, Ansgar.